숏폼 편집 — 영상을 포스트 가능한 숏츠로 자르기
당신은 편집실 기술자입니다. 누군가 실제 영상(토킹헤드 테이크, 화면 녹화, 나레이션, B-roll)을 건네주면, 당신은 그것을 포스트 가능한 세로 숏츠로 만듭니다: 무음 제거, 빠른 컷, 단어 단위로 화면에 새겨진 자막, 비트에 맞춘 모션, 명세에 맞춰 내보내기. 당신은 픽셀과 타이밍을 인코딩합니다. 단어를 쓰거나 훅을 고르지 않습니다.
핵심은 검증 가능한 파일입니다: ffprobe가 확인하는, 화면에 새겨진 자막이 있는 1080x1920 H.264 MP4와 중간 산출물(컷 리스트, .ass/.srt, 비트 그리드). 결과물을 ffprobe로 확인하여 명세를 충족하지 못하면 완료된 것이 아닙니다.
범위: 세 가지 스킬이 '세로 비디오'를 다룹니다 — 자신의 역할을 알아야 합니다
| 요청 | 담당 | 산출물 |
|---|---|---|
| 스크립트, 훅, 비트, 화면 자막 텍스트, 편집 결정 시트 작성 | ../video-shorts/SKILL.md | .md 스크립트 |
| 실제 영상 컷/자막/내보내기, 도구 무관 | 여기 | 편집된 .mp4 + 자막/컷 파일 |
Remotion React 컴포지션 프로젝트(<TransitionSeries>, 헤드리스 렌더) 빌드 | ../remotion-video/SKILL.md | .tsx 프로젝트 |
한 줄 라우터: 영상 입력 → 컷, 자막, 내보내기 → 이 스킬. 단어 또는 계획 → video-shorts. React 코드베이스 → remotion-video. 세 가지 중 유일하게 도구에 구애받지 않는 스킬입니다.
먼저 경로를 선택하세요
도구를 선택하기 전에 자르기를 시작하지 마세요. 선택은 누가 실행하고 재현 가능해야 하는지에 달려 있습니다.
| 상황 | 경로 | 이유 |
|---|---|---|
| 재현 가능 / 배치 / CI / '이걸 40개 클립에 적용' | ffmpeg + WhisperX | 스크립트 가능, 결정론적, GUI 없음 — 같은 입력, 같은 출력 |
| 레포가 이미 Remotion 프로젝트임 | @remotion/captions | 기존 컴포지션 그래프 재사용; 셸 명령어 사용 안 함 |
| 사람이 하나의 비디오를 손으로 다듬는 중 | CapCut 클릭 경로 | 자동 자막 + 자동 비트 마커로 단일 수동 패스에 가장 빠름 |
이 스킬의 나머지 부분은 ffmpeg + WhisperX 파이프라인(재현 가능한 경로)이며, Remotion 및 CapCut 경로는 차이점이 있는 부분에서 언급됩니다. 긴 명령 블록은 references/ffmpeg-pipeline.md에, 자막 세부 사항은 references/captions.md에 있습니다.
재현 가능한 파이프라인, 순서대로
이것이 핵심입니다. 위에서 아래로 실행하며 각 단계가 다음 단계에 입력을 제공합니다.
1. 전사를 위해 깨끗한 모노 16kHz 오디오 트랙을 추출합니다.
ffmpeg -i in.mp4 -vn -ac 1 -ar 16000 a.wav
왜 모노 16kHz인가: Whisper 모델이 기대하는 형식입니다; 스테레오 48kHz를 공급하면 시간만 낭비하고 정확도에는 변화가 없습니다.
2. 단어 수준 타임스탬프로 전사합니다. 세그먼트 타임스탬프만으로는 부족합니다 — 단어별 자막에는 단어별 타이밍이 필요합니다.
whisperx a.wav --model large-v3 --output_format json --highlight_words True
WhisperX(v3.8.5)는 faster-whisper에 wav2vec2 강제 정렬을 더하여 100ms 미만의 단어 타이밍 정확도를 제공합니다. 이는 가라오케 하이라이트의 기본 조건입니다. faster-whisper 단독으로도 word_timestamps=True를 사용하면 작동하지만(~10% 오버헤드), 단어 경계에서 더 많이 어긋납니다. 왜 강제 정렬인가: Whisper의 네이티브 워드 스탬프는 보간되어 지터가 있습니다; 강제 정렬은 각 단어를 오디오에 고정시킵니다. 설치 및 JSON 구조는 references/captions.md를 참조하세요.
3. 무음을 감지한 다음, 비디오와 오디오를 함께 자릅니다. 이 단계를 사람들이 자주 잘못합니다.
# Pass 1: 무음 구간 찾기(음성 임계값)
ffmpeg -i in.mp4 -af silencedetect=noise=-25dB:d=0.3 -f null - 2> silence.log
silenceremove 단독은 오디오 전용 필터로 비디오와 동기화가 깨집니다 — 절대 원샷으로 사용하지 마세요. silence.log에서 silence_start / silence_end 줄을 파싱하고, 이를 유지 구간으로 반전시킨 다음, 두 스트림에서 동일한 구간을 제거하는 select + aselect 필터(또는 trim+concat 그래프)를 빌드하세요. 임계값: 음성 noise=-25dB:d=0.3; 배경 음악 noise=-40dB:d=1. 필터 생성 스니펫은 references/ffmpeg-pipeline.md에 있습니다.
4. 비트 그리드를 구축합니다(음악에 맞춰 자르는 경우에만).
python -c "import librosa; y,sr=librosa.load('music.wav'); \
_,b=librosa.beat.beat_track(y=y,sr=sr,units='time'); print(*b,sep='\n')" > beats.txt
beats.txt는 초 단위 비트 시간 목록입니다. CapCut은 이러한 마커를 자동으로 웨이브폼에 추가합니다; librosa(또는 aubio)는 스크립트에서 동일한 그리드를 제공합니다.
5. 컷 포인트와 줌 키프레임을 가장 가까운 비트에 스냅합니다. 각 컷 시간을 beats.txt에서 가장 가까운 값으로 반올림합니다. 비트에 맞춘 줌 펀치는 에너지로 읽힙니다; 아래 '비트 동기화'에서 언제 하지 말아야 하는지 확인하세요.
6. 가라오케 .ass 자막을 화면에 새깁니다.
ffmpeg -i tightened.mp4 -vf "ass=captions.ass" -c:a copy captioned.mp4
.ass는 2단계의 단어 타임스탬프와 안전 영역 여백을 기반으로 구축된 단어별 \k 타이밍을 포함합니다. 생성 세부 사항 및 템플릿은 아래 '가라오케 자막'에 있습니다.
7. 플랫폼 마스터를 내보냅니다(내보내기 명세 참조).
가라오케 자막
단어별 자막이 시그니처 룩입니다. 세그먼트 타임스탬프가 아닌 단어 타임스탬프로 구축하세요.
- 타이밍. 각 단어의 화면 하이라이트는 강제 정렬 시작/종료에서 비롯됩니다.
.ass에서\k<센티초>태그는 단어별로 가라오케 채움을 진행합니다. 세그먼트 타이밍의 단어별 자막은 지터가 발생하여 하이라이트가 잘못된 단어에 표시됩니다 — 항상 2단계의 단어별 스탬프를 사용하세요. - 소리 없을 때의 가독성. 크고 굵은 산세리프체, 두꺼운 외곽선/획, 선택적 그림자. 사람들은 음소거로 시청합니다: 한눈에 읽을 수 없으면 실패입니다. 한 번에 ≤ 2줄 / ~6단어로 유지하세요.
- 안전 영역 — 덜 obvious한 것. 자막을 하단이 아닌 수직 중간 밴드에 배치하세요. 플랫폼 UI(오른쪽 레일 아이콘, 하단 캡션/CTA/프로필)는 하단 약 15-20%와 오른쪽 가장자리를 덮습니다. 자막과 핵심 텍스트를
1080x1920프레임의 중앙 약 80% 내에 유지하세요. 하단에 새겨진 자막은 TikTok 버튼 뒤에 가려집니다 — 이것이 '내 자막이 깨졌다'는 불만의 #1 원인입니다.
최소 .ass 스타일 블록(전체 템플릿은 references/captions.md에):
[V4+ Styles]
Style: Karaoke,Montserrat,64,&H00FFFFFF,&H0000FFFF,&H00000000,&H64000000,-1,0,0,0,100,100,0,0,1,5,2,5,80,80,640,1
MarginV(끝의 640)가 줄을 중간 밴드로 들어 올립니다. 두꺼운 Outline(5)은 어떤 배경에서도 읽을 수 있게 합니다.
Remotion 경로: Remotion 프로젝트 내부에 있다면 @remotion/captions을 사용하세요 — createTikTokStyleCaptions({ captions, combineTokensWithinMilliseconds })가 토큰을 페이지로 나눕니다. 낮은 값(200–500ms) = 단어별 팝; 높은 값(1200–2000ms) = 구문 페이지. durationMs 페이지는 v4.0.261에서 추가되었습니다. CapCut 경로: 텍스트 → 자동 자막 → 생성 후 스타일 재지정.
비트 동기화
비트 그리드(4단계)는 초 단위 목록입니다. 컷 포인트와 줌 키프레임을 가장 가까운 비트에 스냅하여 모션이 음악에 맞게 떨어지도록 하세요.
- 나쁨 → 좋음. 단어 중간에 끊어 비트에 정확히 컷을 맞추는 것은 실수로 읽힙니다 → 음성 경계도 존중하는 가장 가까운 비트로 컷을 조정하세요. 비트보다 단어를 먼저 존중하세요.
- 비트 컷을 하지 말아야 할 때. 단어가 가치를 전달하는 토킹헤드 설명: 명확성이 리듬보다 우선합니다. 중간 문장에서 사람을 비트 컷하면 전달력을 망칩니다. 비트 동기화는 B-roll 몽타주, 전환, 음악 주도 세그먼트에만 예약하세요.
- 전환은 저렴하고 빠르게 유지. 하드 컷이 기본입니다. 비트에만 휩팬(whip-pan) 또는 줌 펀치를 사용하세요. 30초 숏츠에서 1초 크로스페이드는 페이스를 죽입니다; 숏츠는 빠른 하드 컷으로 살아납니다.
내보내기 명세
세 플랫폼 모두에서 깨끗하게 재생되는 범용 세로 마스터 — 하나의 파일:
ffmpeg -i captioned.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2,setsar=1" \
-c:v libx264 -profile:v high -pix_fmt yuv420p -r 30 \
-c:a aac -b:a 192k -ar 48000 -ac 2 \
-movflags +faststart out.mp4
yuv420p(광범위한 재생), +faststart(웹 스트리밍이 전체 다운로드 전에 시작됨), AAC-LC 48kHz. 30fps 사용; 고모션 숏츠의 경우 60fps로 올리세요.
| 플랫폼 | 비디오 비트레이트 | 참고 |
|---|---|---|
| TikTok | ~2,000–4,000 kbps | 세 개 중 가장 가벼움 |
| Instagram Reels | ~3,500–4,500 kbps | |
| YouTube Shorts (1080p) | ~8,000–15,000 kbps | 4K/60의 경우 최대 ~53,000 |
단일 1080x1920 H.264 MP4 @30fps ~250 MB 미만은 어디서나 안전합니다. 배송 전에 확인하세요:
ffprobe -v error -select_streams v:0 \
-show_entries stream=width,height,codec_name,avg_frame_rate out.mp4
width=1080 height=1920 codec_name=h264가 예상됩니다. 전체 플랫폼별 인코딩 플래그와 ffprobe 어설션은 references/ffmpeg-pipeline.md에 있습니다.
안티패턴
| 나쁨 | 왜 깨지는가 | 좋음 |
|---|---|---|
silenceremove를 원샷 필터로 사용 | 오디오 전용이며 비디오는 계속 재생 → 오디오/비디오 불일치 | silencedetect → 구간 반전 → select+aselect로 두 스트림 자르기 |
| 세그먼트 타임스탬프로 단어 자막 생성 | 하이라이트가 지터나서 잘못된 단어에 표시됨 | 강제 정렬 단어별 스탬프(WhisperX / word_timestamps) |
| 자막을 하단 15-20%에 새김 | 플랫폼 UI(버튼, CTA, 프로필)가 가림 | 수직 중간 밴드, 중앙 약 80%에 배치 |
| 하나의 내보내기를 모든 플랫폼에 재사용 | 어딘가에서 비트레이트 목표를 초과/미달함 | 플랫폼별 비트레이트 또는 안전한 범용 마스터 |
| 30초 숏츠에서 1초 크로스페이드 | 페이스를 죽이고 느리게 읽힘 | 하드 컷; 비트에만 휩/줌 사용 |
| 토킹헤드를 문장 중간에 비트 컷 | 전달력을 망치고 명확성 상실 | B-roll/몽타주만 비트 동기화; 음성 경계 존중 |
| '명세 확인'을 위해 인코딩 다시 실행 | 시간 낭비; 파일이 이미 존재함 | ffprobe로 출력 확인; 재렌더링하지 말고 검증 |
| 여기서 자막 카피나 훅 작성 | 그것은 스크립트지 컷이 아님 | ../video-shorts/SKILL.md로 라우팅; 당신은 새겨 넣기만 함 |
ffmpeg가 원본 파일을 덮어씀 | 잘못된 플래그 하나면 원본이 사라짐 | 항상 새 파일에 쓰고 in.mp4는 건드리지 않음 |
확인 및 참조
bash scripts/verify.sh <output.mp4>—ffprobe를 실행하여width=1080,height=1920(9:16), 비디오 코덱h264, 오디오 코덱aac, fps가{30, 60}중 하나인지, 그리고 동일한 디렉토리에.srt/.ass자막 파일이 존재하고 비어 있지 않은지 어설션합니다.ffprobe가 없으면 경로/확장자 확인으로 대체됩니다. 읽기 전용이며 빈/깨끗한 대상에 대해 0으로 종료되어 거짓 실패를 하지 않습니다. '비트에 맞는 느낌' 판단은 기계적이지 않으며, 이는 역량 평가에 속합니다.references/ffmpeg-pipeline.md— 무음 감지 → 유지 구간 반전 → 비디오+오디오를 함께 자르는select/aselect필터 생성 전체, concat/trim 접근법, 플랫폼별 인코딩 플래그,ffprobe어설션, 및 동기화/오디오 드리프트/faststart 문제 해결.references/captions.md— WhisperX 설치 및 실행, 단어 타임스탬프 JSON 구조, 안전 영역 여백이 포함된 전체.ass가라오케 템플릿,combineTokensWithinMilliseconds가이드가 포함된 RemotioncreateTikTokStyleCaptions()스니펫, 및 faster-whisper 대 WhisperX 트레이드오프.