Video Cut
Ein langes unbearbeitetes Video wird in einen kompakten, ansehbaren Erstschnitt verwandelt – entscheidungsfreudig, inhaltsbewusst und selbstgeprüft. Der Mensch (Sie, das Modell) trifft die redaktionelle Entscheidung, WAS behalten wird; die gebündelten Skripte übernehmen die mechanische Präzision (Grenzanpassung, Leerlauf-Wiederherstellung, speichersicheres Rendern, Selbstprüfung).
Wann verwenden
- Ein rohes/unbearbeitetes Video (YouTube-URL oder lokale Datei) muss zu einem engeren Schnitt werden.
- Die Anforderung lautet „Halbieren“, „die langweiligen Teile herausschneiden“, „einen ersten/rohen Schnitt erstellen“.
- NICHT für: Wort-für-Wort-Mikrochirurgie bei Füllwörtern, Multi-Kamera-B-Roll-Montage, Farb-/Audiokorrektur – das sind spätere P1/P2-Politur-Durchgänge. Diese Fähigkeit ist P0: Diagnose validieren + einen soliden Schnitt erstellen.
Abhängigkeiten
/video-understand ist eine Voraussetzung. Führen Sie es zuerst aus und verwenden Sie dessen validierte Medien, Transkript, Analyse und Zeitleiste anstatt sie in dieser Fähigkeit neu zu erstellen. Überprüfen Sie vor dem Start, ob es installiert ist. Wenn nicht, warnen Sie den Benutzer, dass diese Voraussetzung fehlt, und stoppen Sie, bevor Sie Medien verarbeiten.
Aktivieren Sie eine beliebige Umgebung, die diese Komponenten enthält (gehen Sie NICHT von einem bestimmten Conda-Umgebungsnamen aus):
yt-dlp(Download),ffmpeg/ffprobe(Schnitt/Rendering/Prüfung) im PATH- Python mit
faster-whisper(CPU funktioniert:device=cpu, compute_type=int8) Überprüfen Sie zuerst:yt-dlp --version,ffmpeg -version,python -c "import faster_whisper".
Projektprotokoll-Workflow
Verwenden Sie diese dauerhaften Projektdateien:
work/cut/edit-plan.json # nur selbst verfasste keep/drop-Entscheidungen
work/timeline.json # generierte Präzisionsbereiche + Quell-/Programmzuordnung
review/01-cut/cut-summary.md
review/01-cut/timeline-map.png
review/01-cut/boundary-review.mp4
review/01-cut/full-proxy.mp4 # optional: gesamte Programm-Nachverfolgung
Jede kanonische Entscheidung hat eine stabile id, action (keep oder drop), start_s,
end_s, reason und semantische/Transkript-evidence_refs. Keep-Entscheidungen sind chronologisch;
V1 unterstützt keine neu angeordneten oder duplizierten Quellclips.
Wiederverwenden Sie die gemeinsame Beweisebene, anstatt erneut zu transkribieren oder zu diagnostizieren:
python skills/video-understand/scripts/transcribe.py work/cache/audio16k.wav work/understand/transcript
python skills/video-understand/scripts/analyze.py work/understand/transcript.json work/understand/analysis.json
Die vorhandenen Präzisionsskripte akzeptieren den kanonischen Plan. Erweitern Sie wortgeschützte Grenzen, weisen Sie optional lineare variable Geschwindigkeit zu und generieren Sie dann die gemeinsame Zeitleiste:
python skills/video-cut/scripts/build_edit.py work/cut/edit-plan.json work/understand/transcript.json work/cache/edit-final.json
python skills/video-cut/scripts/assign_speed.py work/cache/edit-final.json work/understand/transcript.json
python skills/video-understand/scripts/build_timeline.py work/cache/edit-final.json work/timeline.json --fps-num SOURCE_FPS_NUM --fps-den SOURCE_FPS_DEN
Verwenden Sie die exakte rationale FPS aus work/understand/media.json; runden Sie niemals 30000/1001 auf
30/1. Überprüfen Sie timeline-map.png und das kurze boundary-review.mp4. Generieren Sie
full-proxy.mp4 nur, wenn die gesamte Programm-Nachverfolgung überprüft werden muss. Schreiben Sie das Ergebnis in
cut-summary.md und verweisen Sie den Betriebsprüfungsbericht auf diese Datei.
Zeichnen Sie den Zeitleistenbeitrag mit seiner erforderlichen Quelleingabe auf, aktualisieren Sie die Betriebs-Ganzzahl
revision und setzen Sie based_on auf die genaue verwendete Understanding-Revision:
"render": {
"kind": "timeline-transform",
"input": "../input/original-video.mp4",
"plan": "timeline.json"
}
Der gemeinsame Auslieferungsrenderer codiert die aktive Sequenz, nachdem alle Revisionsprüfungen bestanden sind.
Standalone-Kompatibilitäts-Workflow
Die untenstehenden Legacy-Dateien und -Befehle bleiben während der Migration unterstützt. build_edit.py
akzeptiert sowohl edit_coarse.json als auch kanonische decisions[]; cut_render.py akzeptiert sowohl
edit_final.json als auch timeline.json; das transcribe.py dieser Fähigkeit ist ein
Kompatibilitäts-Wrapper um ../video-understand/scripts/transcribe.py.
Behalten Sie alle Zwischendateien unter work/ und liefern Sie sie im Projektstammverzeichnis aus:
work/source.mp4 # heruntergeladenes Original
work/audio16k.wav # 16k Mono-Audio für Whisper
work/transcript.json/.srt # Wort-Zeitstempel
work/analysis.json # Diagnose (Stille, Füller, Läufe)
work/edit_coarse.json # *** IHRE redaktionelle Entscheidung (handgeschrieben) ***
work/edit_final.json # erweiterte, enge Render-Segmente (generiert; enthält geschwindigkeit pro Segment)
work/selfcheck/ # Schnitt-Neu-Transkription + Frame-Zusammenfügung
first_cut.mp4 # DAS AUSLIEFERUNGSERGEBNIS
first_cut_report.md # Schnitt- + Selbstprüfungsbericht
Die Pipeline (6 Schritte)
1. Herunterladen
Höchste erreichbare Qualität + Audio. Der Standard-Player-Client schlägt oft fehl (nicht verfügbar / DRM / Anmeldung). Der zuverlässige Fallback ist der android-Client:
yt-dlp --extractor-args "youtube:player_client=android" \
-o work/source.mp4 "<URL>"
Wenn nur ein gemuxter 360p (Format 18) ohne Anmeldung erreichbar ist, akzeptieren Sie es und dokumentieren Sie die Einschränkung – HD DASH ist häufig DRM-/Anmelde-geschützt. Extrahieren Sie dann das Audio:
ffmpeg -y -i work/source.mp4 -ac 1 -ar 16000 work/audio16k.wav
2. Transkribieren (wortgenau)
python scripts/transcribe.py work/audio16k.wav work/transcript [base.en]
Erzeugt work/transcript.json (Segmente + Start/Ende pro Wort) und .srt.
faster-whisper, CPU/int8, VAD an, word_timestamps=True.
Nicht-Englisch: Übergeben Sie ein mehrsprachiges Modell + --lang, z.B.
python scripts/transcribe.py work/audio16k.wav work/transcript medium --lang zh
(die .en-Modelle sind nur für Englisch). Überprüfen Sie die Sprache zuerst an einer kurzen Probe.
Hinweis: Whisper entfernt die meisten vokalisierten „hm/äh“ – SIE SIND NICHT IM TRANSKRIPT MESSBAR,
Daher muss die Füllererkennung die lexikalische Wortsuche unten mit der Stillelückenanalyse kombinieren
und sich nicht allein auf den Transkripttext verlassen.
3. Diagnostizieren („sehen“ + „lesen“)
python scripts/analyze.py work/transcript.json work/analysis.json
Erkennt: Führende/nachlaufende Stille, Wortzwischenstille ≥0.8s (mit dem Wort, dem sie folgt), Fülleranzahl, WPM, Sprechverhältnis, nahezu identische Wiederholungen, Monologe >40s (Kandidaten für Abschweifungen).
Um das Bild zu sehen, entnehmen Sie etwa alle 2s ein Bild in ein Kontaktblatt und lesen Sie es selbst; bestätigen Sie die Szenenstruktur / suchen Sie schwarze oder fehlerhafte Bilder:
ffmpeg -y -i work/source.mp4 -vf "fps=1/2,scale=240:-1,tile=10x10" -frames:v 1 work/contact.png
ffmpeg -i work/source.mp4 -vf "blackdetect=d=0.1:pic_th=0.98" -an -f null -
Bei einer einzelnen statischen Talking-Head-Aufnahme gibt es keine Szenenschnitte – erwarten Sie dies, und beachten Sie, dass die späteren Sprungschnitte normal sind, keine Störungen.
4. Über den Schnitt entscheiden – edit_coarse.json VON HAND schreiben
Dies ist der redaktionelle Kern. Lesen Sie das Transkript + die Analyse und schreiben Sie dann einen groben Plan
von keep-Blöcken und drop-Spannen, die die gesamte Zeitleiste lückenlos/überlappungsfrei kacheln,
jeweils mit in, out und einem einzeiligen reason. Komprimieren Sie langsame Einleitungen auf einige
aussagekräftige Nuggets; behalten Sie Substanz als große Blöcke; entfernen Sie klare Abschweifungen/Geschwafel.
Behalten Sie die chronologische Reihenfolge bei; die kanonische V1-Zeitleiste lehnt Neuordnungen ab.
Zielen Sie darauf ab, die Laufzeit etwa zu halbieren.
- Formatspezifikation + ein reales Arbeitsbeispiel:
reference/edit_coarse.schema.md. - Richten Sie jede Blockgrenze an einem Satz-/Klauselende aus – beginnen/stoppen Sie niemals
mitten im Satz oder bei einem Stottern. Verwenden Sie:
Es akzeptiert sowohl Legacy-python scripts/inspect_bounds.py work/edit_coarse.json work/transcript.jsonkeep[]- als auch kanonischedecisions[]-Pläne und gibt die Wörter aus, die jede Grenze überspannen, sodass Sie sie auf saubere Kanten verschieben können.
5. Erweitern → Auto-Geschwindigkeit → Rendern
Wandeln Sie grobe Blöcke in enge, störungsfreie Render-Segmente um, normalisieren Sie das Sprechtenpo, und rendern Sie dann:
python scripts/build_edit.py work/edit_coarse.json work/transcript.json work/edit_final.json 1.5
python scripts/assign_speed.py work/edit_final.json work/transcript.json # fügt Geschwindigkeit pro Segment hinzu
python scripts/cut_render.py work/edit_final.json work/source.mp4 first_cut.mp4
build_edit.pyteilt jeden Block bei internen Pausen > SPLIT_GAP (4. Argument, z.B. 1.5s) und trimmt jede Grenze IN DIE STILLE (LEAD 0.10s / TRAIL 0.30s), sodass kein Wort abgeschnitten wird und Stille zurückgewonnen wird. Niedrigerer SPLIT_GAP = enger, aber abgehackter; für einen langsamen, bedächtigen Sprecher bevorzugen Sie ~1.5, nicht 0.6 (vermeidet zuckende Mikroschnitte).assign_speed.py(automatische variable Geschwindigkeit) – gruppiert Render-Segmente nachdecision_ref, misst das Sprechtenpo jeder selbst verfassten keep-Entscheidung und schreibt einen gemeinsamenspeed-Faktor plus die resultierendeout_durjedes Segments zurück inedit_final.json. Tempo bereits innerhalb des Komfortbandes bleibt bei 1.0; außerhalb des Bandes bewegt es sich nur zum nächsten Grenzwert des Komfortbandes. Benachbarte Entscheidungsblöcke unterscheiden sich um höchstens 0.08x, um „pumpende“ Übergänge zu vermeiden. Es ändert nur das Tempo – niemals, welcher Inhalt behalten wird. Lesen Sie die gedruckte Tabelle vor dem Rendern:- Metrik: Wörter/Minute (Englisch) – wechselt automatisch zu Zeichen/Minute für CJK (zh/ja/ko).
- Standardwerte sind Erstlauf-Startpunkte, keine validierten Konstanten: Komfortband 145–185 WPM und Geschwindigkeit begrenzt auf 1.0–1.3. Dies ist nur Beschleunigung: langsame Entscheidungsblöcke können gestrafft werden, während natürliche schnelle Lieferung bei 1.0 bleibt. Kurze Entscheidungsblöcke (<3.5s / <6 Wörter) sind zu verrauscht, um gemessen zu werden, und übernehmen den globalen Faktor.
- Die Rate wird nach der Stille-Rückgewinnung gemessen, daher liest sie sich höher als der Brutto-WPM und ist
näher an der Artikulationsrate. Die Überprüfung der gedruckten Tabelle ist tragend: überfliegen Sie sie
und stimmen Sie
deadbandauf den Sprecher ab, bevor Sie rendern, vertrauen Sie nicht blind den Standardwerten. - Einstellungen (k=v):
mode=segment|global|off(Standardsegment;global=ein Faktor für das gesamte Video,off=deaktivieren),deadband=lo,hi,min_speed=/max_speed=,min_seg=/min_words=,lang=auto|en|cjk. Um die Funktion vollständig zu überspringen, führen Sie diesen Schritt einfach nicht aus –cut_render.pybehandelt eine fehlendespeedals 1.0.
cut_render.pyverwendet N separate gesuchte Eingaben + concat-Filter, einzelne Neucodierung. Dies ist zwingend: N-maliges Trimmen von EINER decodierten Eingabe bewirkt, dass ffmpeg den gesamten decodierten Stream puffert (zig GB für ein langes Video). Siehereference/pitfalls.md. Wenn Segmente einespeedtragen, passt es die Zeitsteuerung jeder Eingabe an (setptsVideo /atempoAudio) und normalisiert fps/Zeitbasis/Abtastrate pro Eingabe vor dem Concat, sodass A/V synchron bleibt; ohne Geschwindigkeit fällt es auf den exakten Originalgraphen zurück.- Abschließender Vergleich:
video-edit-compareliest die kanonische Zeitleiste plus die tatsächliche endgültige Auslieferung. Es projiziert endgültige Pixel zurück auf die Quellzeit, dehnt varispeed-Clips auf ihre Quellendauer und zeigt verworfene Bereiche als Schwarz an.
6. Selbstprüfung – nicht als erledigt erklären, bis dies bestanden ist
# Protokoll-Präzisions-Regressionsprüfung (vom Repository-Stammverzeichnis aus ausführen)
python skills/video-cut/scripts/check_project_protocol.py
# den fertigen Schnitt neu transkribieren
ffmpeg -y -i first_cut.mp4 -ac 1 -ar 16000 work/selfcheck/cut_audio16k.wav
python scripts/transcribe.py work/selfcheck/cut_audio16k.wav work/selfcheck/cut_transcript
# Inhalts- + Füller- + Grenzprüfung
python scripts/verify_cut.py work/edit_final.json work/transcript.json work/selfcheck/cut_transcript.json
# Bild- / Schwarz- / Verbindungsprüfung (Verbindungszeiten verwenden die out_dur nach der Geschwindigkeit, daher bleiben sie genau)
python scripts/selfcheck_frames.py work/edit_final.json first_cut.mp4 work/selfcheck
# A/V-Synchronisation + keine verbleibende Stille
ffprobe -v error -select_streams v:0 -show_entries stream=duration -of csv=p=0 first_cut.mp4
ffprobe -v error -select_streams a:0 -show_entries stream=duration -of csv=p=0 first_cut.mp4
ffmpeg -i first_cut.mp4 -af silencedetect=noise=-32dB:d=1.5 -f null -
Bestandenschwellen:
| Prüfung | Bestandensbedingung |
|---|---|
| Schwarze Bilder | keine |
| Verbindungsbilder | sauber – nur natürliche Kopfsprünge, kein Schwarz/Einfrieren/Riss |
| A/V-Synchronisation | Videodauer vs. Audiodauer innerhalb von ~1 Frame (≈30ms); insgesamt ≈ final_duration_s_after_speed bei varispeed |
| Stille ≥1.5s | 0 (Sprechverhältnis sollte deutlich steigen) |
| Verworfenes/doppeltes Segment | keine – alle wichtigen Inhalte vorhanden (difflib ~0,90 ist OK; niedrigeres Verhältnis ist normalerweise Transkriptionsrauschen des zweiten Durchgangs bei gemurmeltem Sprechen, kein Verlust – durch Schlüsselwort-Präsenz verifizieren, bevor Sie dem Schnitt die Schuld geben) |
| Abgeschnittene Halbsätze | keine – Grenzen landen in Stille / an Satzenden |
Ehrlicher Füller-Vorbehalt: Absatzweises Schneiden wird NICHT „fast keine Füller“ erreichen. Die Dichte pro Minute kann sogar steigen, weil die beibehaltene Substanz gesprächig ist. Berichten Sie dies ehrlich; die Entfernung von Füllwörtern auf Wortebene gehört in P1/P2 (und würde einen Einzel-Talking-Head sichtbar abgehackt machen).
Schließlich
Schreiben Sie first_cut_report.md: Quellenzusammenfassung, was geschnitten wurde & warum, die Selbstprüfungstabelle,
und alle ehrlichen Vorbehalte (Qualitätsgrenze durch 360p-Quelle, Füllerdichte usw.).
Wenn varispeed angewendet wurde, legen Sie es offen: wie viele Segmente zeitlich angepasst wurden und den
Geschwindigkeitsbereich (aus der Tabelle von assign_speed.py / speed_params), sodass der Leser weiß, dass der Schnitt nicht
1:1 Echtzeit ist. Beachten Sie auch, dass die Füller-pro-Minute-Zahl von verify_cut.py nach der Beschleunigung
etwas höher gelesen wird (gleiche Wörter, kürzere Minuten) – ein Darstellungsartefakt, keine hinzugefügten Füller.
Schlüsselprinzipien (die hart erarbeiteten)
- Sie entscheiden über den Inhalt; Skripte entscheiden über die Bilder. Schreiben Sie
edit_coarse.jsonvon Hand; lassen Siebuild_edit.pydie Präzision undassign_speed.pydas Tempo übernehmen. - Geschwindigkeit beeinflusst das Tempo, niemals den Inhalt. Auto-Varispeed gibt allen Render-Segmenten von
einem
decision_refdie gleiche Geschwindigkeit, bewegt außerhalb des Bandes liegendes Tempo nur zum nächsten Grenzwert des Komfortbandes, begrenzt benachbarte Entscheidungen auf ein Delta von 0,08x und begrenzt die Ausgabe auf 1.0–1.3.atempobewahrt die Tonhöhe. Überprüfen Sie die Tabelle;mode=offoder überspringen Sie den Schritt, um zu deaktivieren. - Schneiden Sie niemals ein Wort an. Grenzen fallen immer in die Stille.
- Nur speichersicheres Rendern (N gesuchte Eingaben + concat). Niemals mehrere Trims von einer Eingabe.
- Seien Sie entscheidungsfreudig. Treffen Sie vernünftige Entscheidungen und fahren Sie fort; fragen Sie nicht übermäßig nach.
- Selbstprüfung ist nicht verhandelbar. Neu transkribieren + Bilder prüfen, bevor Sie die Fertigstellung erklären.
- Siehe
reference/pitfalls.mdfür die vollständige Liste der Fallstricke und Korrekturen.