비디오 컷
하나의 긴 원본 동영상을 간결하고 시청 가능한 최초 컷으로 변환합니다 — 결정적이고, 내용을 인지하며, 자체 검증됩니다. 인간(당신, 모델)은 무엇을 남길지에 대한 편집 결정을 내립니다. 번들 스크립트는 기계적 정밀 작업(경계 정렬, 묵음 제거, 메모리 안전 렌더링, 자체 점검)을 수행합니다.
사용 시기
- 날것/편집되지 않은 동영상(YouTube URL 또는 로컬 파일)을 더 짧게 컷해야 할 때
- "반으로 줄여줘", "지루한 부분을 잘라줘", "최초/러프 컷을 만들어줘"와 같은 요청
- 다음에는 사용하지 마세요: 단어 단위 필러 미세 제거, 멀티캠 B-롤 조립, 색보정/오디오 후처리 — 이러한 작업은 이후 P1/P2 단계에서 수행합니다. 이 스킬은 P0 단계입니다: 진단을 검증하고 견고한 컷을 생성합니다.
종속성
/video-understand가 선행 조건입니다. 먼저 실행하고, 이 스킬에서 새로 생성하지 말고 검증된 미디어, 트랜스크립트, 분석 및 타임라인을 재사용하세요. 시작하기 전에 설치되어 있는지 확인하십시오. 설치되어 있지 않으면, 사용자에게 이 선행 조건이 누락되었음을 경고하고 미디어 처리를 시작하기 전에 중단하십시오.
다음 항목이 포함된 환경을 활성화하십시오(특정 conda 환경 이름을 가정하지 마십시오):
yt-dlp(다운로드),ffmpeg/ffprobe(컷/렌더링/프로브)가 PATH에 있어야 함- Python과
faster-whisper(CPU 작동 가능:device=cpu, compute_type=int8) 먼저 확인:yt-dlp --version,ffmpeg -version,python -c "import faster_whisper".
프로젝트 프로토콜 워크플로우
다음 내구성 있는 프로젝트 파일을 사용하십시오:
work/cut/edit-plan.json # 수동으로 작성된 keep/drop 결정만 포함
work/timeline.json # 생성된 정밀 범위 + 소스/프로그램 매핑
review/01-cut/cut-summary.md
review/01-cut/timeline-map.png
review/01-cut/boundary-review.mp4
review/01-cut/full-proxy.mp4 # 선택 사항: 전체 프로그램 페이싱 검토
각 표준 결정에는 안정적인 id, action(keep 또는 drop), start_s, end_s, reason, 의미론적/트랜스크립트 evidence_refs가 있습니다. Keep 결정은 시간순으로 유지합니다. V1은 재정렬되거나 중복된 소스 클립을 지원하지 않습니다.
트랜스크립트나 진단을 다시 수행하지 않고 공유 증거 레이어를 재사용하십시오:
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
기존 정밀 스크립트는 표준 계획을 허용합니다. 단어 안전 경계를 확장하고, 선택적으로 선형 가변 속도를 할당한 다음, 공유 타임라인을 생성합니다:
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
work/understand/media.json의 정확한 유리수 FPS를 사용하십시오. 30000/1001을 30/1로 반올림하지 마십시오. timeline-map.png와 짧은 boundary-review.mp4를 검토하십시오. 전체 프로그램 페이싱을 검토해야 하는 경우에만 full-proxy.mp4를 생성하십시오. 결과를 cut-summary.md에 작성하고, 작업 검사 보고서를 해당 파일로 지정하십시오.
타임라인 기여를 필수 소스 입력과 함께 기록하고, 작업 정수 revision을 업데이트하고, based_on을 소비된 정확한 이해 리비전으로 설정하십시오:
"render": {
"kind": "timeline-transform",
"input": "../input/original-video.mp4",
"plan": "timeline.json"
}
공유 전달 렌더러는 모든 리비전 검사가 통과된 후 활성 시퀀스를 인코딩합니다.
독립형 호환성 워크플로우
마이그레이션 중에도 아래 레거시 파일과 명령어는 계속 지원됩니다. build_edit.py는 edit_coarse.json과 표준 decisions[]를 모두 허용합니다. cut_render.py는 edit_final.json과 timeline.json을 모두 허용합니다. 이 스킬의 transcribe.py는 ../video-understand/scripts/transcribe.py 주변의 호환성 래퍼입니다.
모든 중간 파일을 work/ 아래에 보관하고, 프로젝트 루트에 전달하십시오:
work/source.mp4 # 다운로드된 원본
work/audio16k.wav # whisper용 16k 모노 오디오
work/transcript.json/.srt # 단어 수준 타임스탬프
work/analysis.json # 진단(침묵/필러/런)
work/edit_coarse.json # *** 사용자의 편집 결정(수동 작성) ***
work/edit_final.json # 확장된 정밀 렌더 세그먼트(생성됨, 세그먼트별 속도 포함)
work/selfcheck/ # 컷 재트랜스크립트 + 프레임 결합
first_cut.mp4 # 최종 산출물
first_cut_report.md # 편집 + 자체 점검 보고서
파이프라인(6단계)
1. 다운로드
가장 높은 접근 가능 품질 + 오디오. 기본 플레이어 클라이언트는 자주 실패합니다(not-available / DRM / sign-in). 신뢰할 수 있는 폴백은 android 클라이언트입니다:
yt-dlp --extractor-args "youtube:player_client=android" \
-o work/source.mp4 "<URL>"
로그인 없이 muxed 360p(포맷 18)만 접근 가능한 경우, 이를 수락하고 제약 조건을 문서화하십시오 — HD DASH는 종종 DRM/로그인으로 보호됩니다. 그런 다음 오디오를 추출합니다:
ffmpeg -y -i work/source.mp4 -ac 1 -ar 16000 work/audio16k.wav
2. 트랜스크립트(단어 수준)
python scripts/transcribe.py work/audio16k.wav work/transcript [base.en]
work/transcript.json(세그먼트 + 단어별 시작/종료)과 .srt를 생성합니다.
faster-whisper, CPU/int8, VAD 켜짐, word_timestamps=True.
비영어: 다국어 모델 + --lang을 전달하십시오. 예:
python scripts/transcribe.py work/audio16k.wav work/transcript medium --lang zh
(.en 모델은 영어 전용입니다). 먼저 짧은 샘플에서 언어를 확인하십시오.
참고: Whisper는 대부분의 발성된 "음/어"를 제거합니다 — 이들은 트랜스크립트로 측정 가능하지 않으므로, 필러 감지는 아래의 어휘 단어 검색과 침묵 갭 분석을 결합해야 하며, 트랜스크립트 텍스트에만 의존해서는 안 됩니다.
3. 진단("보기" + "읽기")
python scripts/analyze.py work/transcript.json work/analysis.json
다음을 표시합니다: 앞/뒤 묵음, 단어 간 침묵 ≥0.8초(뒤따르는 단어 포함), 필러 수, wpm, 말하기 비율, 거의 중복되는 반복, 40초 초과 독백(잡담 후보).
화면을 보려면, 약 2초마다 프레임을 샘플링하여 접촉 시트를 만들고 직접 읽으십시오. 장면 구조를 확인하고 검은색/불량 프레임을 찾으십시오:
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 -
단일 정적 토킹헤드 샷의 경우 장면 전환이 없습니다 — 이를 예상하고 이후 점프 컷이 정상이며 결함이 아님을 참고하십시오.
4. 컷 결정 — edit_coarse.json을 직접 작성
이것이 편집의 핵심입니다. 트랜스크립트 + 분석을 읽은 다음, 전체 타임라인을 간격이나 중복 없이 타일링하는 keep-블록 및 drop-범위의 대략적인 계획을 작성하십시오. 각각 in, out 및 한 줄짜리 reason을 포함합니다. 느린 서문을 몇 가지 고가치 요점으로 압축하고, 내용을 큰 블록으로 유지하며, 명확한 여담/잡담은 삭제하십시오. 시간순을 유지하십시오. 표준 V1 타임라인은 재정렬을 거부합니다. 실행 시간을 대략 절반으로 줄이는 것을 목표로 하십시오.
- 형식 사양 + 실제 작업 예제:
reference/edit_coarse.schema.md. - 모든 블록 경계를 문장/절 끝에 정렬하십시오 — 문장 중간이나 말더듬에서 시작/중단하지 마십시오. 다음을 사용하십시오:
이는 레거시python scripts/inspect_bounds.py work/edit_coarse.json work/transcript.jsonkeep[]와 표준decisions[]계획을 모두 허용하며 각 경계에 걸쳐 있는 단어를 출력하여 깔끔한 가장자리로 조정할 수 있도록 합니다.
5. 확장 → 자동 속도 → 렌더링
대략적인 블록을 묵음이 없는 정밀 렌더 세그먼트로 변환하고, 말하기 속도를 정규화한 다음 렌더링합니다:
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 # 세그먼트별 속도 추가
python scripts/cut_render.py work/edit_final.json work/source.mp4 first_cut.mp4
build_edit.py는 각 블록을 내부 일시 중지 > SPLIT_GAP(4번째 인수, 예: 1.5초)에서 분할하고 모든 경계를 침묵 안으로 다듬습니다(LEAD 0.10s / TRAIL 0.30s). 이렇게 하면 어떤 단어도 잘리지 않고 묵음이 제거됩니다. SPLIT_GAP이 낮을수록 더 타이트하지만 더 거칠어집니다. 느리고 신중한 화자의 경우 0.6이 아닌 ~1.5를 선호하십시오(지나치게 급격한 미세 컷 방지).assign_speed.py(자동 가변 속도) — 렌더 세그먼트를decision_ref로 그룹화하고, 각 수동으로 작성된 keep 결정의 말하기 속도를 측정한 다음, 하나의 공유speed계수와 각 세그먼트의 결과out_dur를edit_final.json에 다시 씁니다. 이미 편안한 대역 내에 있는 속도는 1.0으로 유지됩니다. 대역 외 속도는 가장 가까운 불감대 가장자리로만 이동합니다. 인접한 결정 블록은 최대 0.08x 차이를 두어 "펌프질" 결합을 방지합니다. 이는 내용이 아닌 속도만 변경합니다. 렌더링하기 전에 인쇄된 표를 읽으십시오:- 지표: 분당 단어 수(영어) — CJK(zh/ja/ko)의 경우 분당 문자 수로 자동 전환됩니다.
- 기본값은 첫 실행 시작점이며 검증된 상수가 아닙니다: 불감대 145–185 WPM 및 속도 제한 1.0–1.3. 이것은 속도 향상 전용입니다: 느린 결정 블록은 조여질 수 있는 반면, 자연스럽게 빠른 전달은 1.0으로 유지됩니다. 짧은 결정 블록(<3.5s / <6 단어)은 측정하기에 너무 노이즈가 많아 전역 계수를 상속합니다.
- 속도는 묵음 제거 후 측정되므로 총 WPM보다 높게 읽히고 조음 속도에 더 가깝습니다. 인쇄된 표 검토는 중요합니다: 렌더링하기 전에 화자의
deadband를 살펴보고 조정하고, 기본값을 맹목적으로 신뢰하지 마십시오. - 설정(k=v):
mode=segment|global|off(기본값segment,global=전체 비디오에 대한 하나의 계수,off=비활성화),deadband=lo,hi,min_speed=/max_speed=,min_seg=/min_words=,lang=auto|en|cjk. 이 기능을 완전히 건너뛰려면 이 단계를 실행하지 마십시오 —cut_render.py는 누락된speed를 1.0으로 처리합니다.
cut_render.py는 N개의 개별 seek 입력 + concat 필터, 단일 재인코딩을 사용합니다. 이것은 필수입니다: 하나의 디코딩된 입력에서 N번 트리밍하면 ffmpeg가 전체 디코딩된 스트림(긴 비디오의 경우 수십 GB)을 버퍼링합니다.reference/pitfalls.md를 참조하십시오. 세그먼트가speed를 전달하면 각 입력을 재시간 조정하고(setpts비디오 /atempo오디오) fps/타임베이스/샘플레이트를 입력별로 정규화한 후 concat하여 A/V가 고정되도록 합니다. 속도가 없으면 정확한 원본 그래프로 대체됩니다.- 최종 비교:
video-edit-compare는 표준 타임라인과 실제 최종 전달을 읽습니다. 최종 픽셀을 소스 시간으로 역투영하고, 가변 속도 클립을 소스 기간으로 늘리고, 드롭된 범위를 검은색으로 표시합니다.
6. 자체 점검 — 이 검사가 통과할 때까지 완료 선언 금지
# 프로토콜 정밀 회귀 검사(저장소 루트에서 실행)
python skills/video-cut/scripts/check_project_protocol.py
# 완성된 컷 재트랜스크립트
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
# 내용 + 필러 + 경계 검사
python scripts/verify_cut.py work/edit_final.json work/transcript.json work/selfcheck/cut_transcript.json
# 프레임 / 검은색 / 결합 검사(결합 시간은 속도 후 out_dur 사용하므로 정확함)
python scripts/selfcheck_frames.py work/edit_final.json first_cut.mp4 work/selfcheck
# A/V 동기화 + 잔여 묵음 없음
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 -
통과 임계값:
| 검사 | 통과 조건 |
|---|---|
| 검은색 프레임 | 없음 |
| 결합 프레임 | 깔끔함 — 자연스러운 헤드 점프만, 검은색/고정/찢어짐 없음 |
| A/V 동기화 | 비디오와 오디오 길이가 ~1프레임 이내(≈30ms), 가변 속도 켜진 경우 총 ≈ final_duration_s_after_speed |
| 묵음 ≥1.5초 | 0(말하기 비율이 현저히 증가해야 함) |
| 드롭/중복 세그먼트 | 없음 — 모든 주요 내용 존재(difflib ~0.90은 허용됨; 더 낮은 비율은 일반적으로 중얼거리는 말에 대한 2차 트랜스크립트 노이즈, 손실이 아님 — 키워드 존재 여부로 확인 후 컷 탓하지 말 것) |
| 잘린 반쪽 문장 | 없음 — 경계가 침묵/문장 끝에 위치 |
정직한 필러 주의: 단락 수준 컷팅은 "필러 거의 없음"을 달성하지 못합니다. 분당 밀도는 오히려 증가할 수 있습니다. 왜냐하면 유지된 내용이 대화 형식이기 때문입니다. 이를 정직하게 보고하십시오. 단어 수준 필러 제거는 P1/P2에 속합니다(단일 샷 토킹헤드를 눈에 띄게 거칠게 만듭니다).
마지막으로
first_cut_report.md를 작성하십시오: 소스 요약, 컷된 내용 및 이유, 자체 점검 표, 그리고 정직한 주의 사항(360p 소스의 품질 한계, 필러 밀도 등). 가변 속도가 적용된 경우, 이를 공개하십시오: 재시간 조정된 세그먼트 수와 속도 범위(assign_speed.py의 표 / speed_params에서 가져옴). 그래야 독자가 컷이 1:1 실시간이 아님을 알 수 있습니다. 또한 verify_cut.py의 분당 필러 수치가 속도 향상 후 약간 더 높게 읽히는 점도 참고하십시오(같은 단어, 더 짧은 분) — 이는 보고 아티팩트이지 추가된 필러가 아닙니다.
핵심 원칙(힘들게 얻은 것들)
- 당신이 내용을 결정하고, 스크립트가 프레임을 결정합니다.
edit_coarse.json을 직접 작성하고,build_edit.py가 정밀 작업을,assign_speed.py가 속도를 처리하게 하십시오. - 속도는 내용이 아닌 속도에만 영향을 줍니다. 자동 가변 속도는 하나의
decision_ref에서 모든 렌더 세그먼트에 동일한 속도를 부여하고, 대역 외 속도만 가장 가까운 불감대 가장자리로 이동시키며, 인접한 결정 차이를 0.08x로 제한하고, 출력을 1.0–1.3으로 고정합니다.atempo는 피치를 보존합니다. 표를 검토하십시오.mode=off로 설정하거나 단계를 건너뛰어 비활성화하십시오. - 단어를 절대 자르지 마십시오. 경계는 항상 침묵 안에 위치합니다.
- 메모리 안전 렌더링만 사용하십시오(N개의 seek 입력 + concat). 하나의 입력을 여러 번 트리밍하지 마십시오.
- 결단력 있게 행동하십시오. 합리적인 판단을 내리고 진행하십시오. 지나치게 묻지 마십시오.
- 자체 점검은 타협할 수 없습니다. 완료를 선언하기 전에 재트랜스크립트 및 프레임 검사를 수행하십시오.
- 함정과 수정 사항의 전체 목록은
reference/pitfalls.md를 참조하십시오.