video-editing
FFmpeg 기반 비디오 편집 자동화 — 자르기, 병합, 포맷 변환, 자막, 워터마크, 속도 조절, 압축, 컬러 보정, 오디오 싱크 등
Video Editing — FFmpeg Automation
FFmpeg 기반 비디오/오디오 편집 자동화 스킬. 자연어 요청을 FFmpeg 명령어로 변환하여 실행.
언제 사용
- ✅ 영상 자르기/trim, 병합/concat
- ✅ 포맷 변환 (mp4, mkv, webm, mov, avi)
- ✅ 해상도/비율 변경 (16:9, 9:16, 1:1, 21:9)
- ✅ 압축/품질 조절 (CRF)
- ✅ 오디오 추출/제거/교체/믹싱
- ✅ 속도 조절 (슬로모션, 타임랩스)
- ✅ 자막 입히기, 워터마크
- ✅ 회전/플립, GIF 변환
- ✅ 썸네일/스크린샷 추출
- ✅ 컬러 스페이스 정규화, 색보정
- ✅ 오디오-비디오 싱크
- ✅ 배치 처리
❌ 사용하지 않음
- 실시간 비디오 편집 UI → DaVinci Resolve/Premiere
- 3D 합성 → After Effects/Blender
- 모션 그래픽 → After Effects
- 화면 녹화 → OBS
도구 선택
| 도구 | 속도 | 용도 |
|------|------|------|
| FFmpeg | 매우 빠름 | CLI 자동화, 프로덕션 파이프라인 |
| MoviePy | 중간 | Python API, 프로그래밍 편집 |
| DaVinci Resolve | 느림 | 수동 정밀 편집 |
⚠️ 핵심 주의사항 (Anti-Patterns)
1. 키프레임 정렬 없이 자르기
# ❌ 잘못됨 — 키프레임 없이 stream copy하면 블랙프레임/깨짐
ffmpeg -i input.mp4 -ss 00:01:23.456 -to 00:02:45.678 -c copy output.mp4✅ 프레임 정밀 컷 (리인코딩)
ffmpeg -i input.mp4 -ss 00:01:23.456 -to 00:02:45.678 \
-c:v libx264 -crf 18 -preset medium -c:a aac -b:a 192k output.mp4✅ 키프레임 정렬 스트림 카피 (빠름, 무손실)
먼저 키프레임 찾기:
ffprobe -select_streams v -show_frames -show_entries frame=pkt_pts_time,key_frame \
-of csv input.mp4 | grep ",1$" | awk -F',' '{print $2}'
가장 가까운 키프레임에서 자르기:
ffmpeg -i input.mp4 -ss 00:01:22.000 -to 00:02:46.000 -c copy output.mp4✅ 최적: Two-pass (빠른 시크 + 정밀 컷)
ffmpeg -ss 00:01:20.000 -i input.mp4 \
-ss 00:00:03.456 -to 00:01:25.678 \
-c:v libx264 -crf 18 -preset medium -c:a aac -b:a 192k output.mp4
2. 불필요한 재인코딩 (품질 손실 누적)
# ❌ 각 작업마다 재인코딩 → 품질 누적 손실✅ 단일 패스에 모든 작업 체인
ffmpeg -ss 00:01:00 -i input.mp4 -i audio.mp3 \
-to 00:04:00 \
-vf "subtitles=subs.srt" \
-map 0:v -map 1:a \
-c:v libx264 -crf 18 -preset medium \
-c:a aac -b:a 192k output.mp4✅ 스트림 카피 활용 — 무손실 작업은 -c copy
ffmpeg -i input.mp4 -ss 00:01:00 -to 00:05:00 -c copy temp.mp4
ffmpeg -i temp.mp4 -i audio.mp3 -map 0:v -map 1:a \
-c:v copy -c:a aac -b:a 192k temp2.mp4
ffmpeg -i temp2.mp4 -vf subtitles=subs.srt \
-c:v libx264 -crf 18 -preset medium -c:a copy output.mp4
3. 컬러 스페이스 무시
# ❌ 다른 컬러 스페이스 영상을 무작정 병합✅ 컬러 분석 후 정규화
ffprobe -v error -select_streams v:0 \
-show_entries stream=color_space,color_transfer,color_primaries,pix_fmt \
-of default=noprint_wrappers=1 clip.mp4BT.601 → BT.709 변환
ffmpeg -i clip.mp4 \
-vf "scale=in_range=full:out_range=limited,colorspace=bt709:iall=bt601:fast=1" \
-color_primaries bt709 -color_trc bt709 -colorspace bt709 \
-c:v libx264 -crf 18 -preset medium -c:a copy clip_normalized.mp4
4. 오디오 싱크 문제
# ❌ 오디오 길이 ≠ 비디오 길이 무시✅ 오디오를 비디오 길이에 맞춤
VIDEO_DUR=$(ffprobe -v error -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 video.mp4)
AUDIO_DUR=$(ffprobe -v error -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 audio.mp3)
TEMPO=$(echo "scale=4; $VIDEO_DUR / $AUDIO_DUR" | bc)
ffmpeg -i video.mp4 -i audio.mp3 \
-filter_complex "[1:a]atempo=$TEMPO[a]" \
-map 0:v -map "[a]" -c:v copy -c:a aac output.mp4
명령어 패턴
포맷 변환
ffmpeg -y -hide_banner -i "INPUT" -c:v libx264 -c:a aac "OUTPUT.mp4"
ffmpeg -y -hide_banner -i "INPUT" -c copy "OUTPUT.mkv"
ffmpeg -y -hide_banner -i "INPUT" -c:v libvpx-vp9 -c:a libopus "OUTPUT.webm"
ffmpeg -y -hide_banner -i "INPUT" -c:v libx264 -c:a aac "OUTPUT.mov"
비율/해상도 변경
# 16:9 YouTube
ffmpeg -y -hide_banner -i input.mp4 \
-vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black" \
-c:a copy output_16x9.mp4
9:16 틱톡/릴스
ffmpeg -y -hide_banner -i input.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black" \
-c:a copy output_vertical.mp4
1:1 인스타그램
ffmpeg -y -hide_banner -i input.mp4 \
-vf "scale=1080:1080:force_original_aspect_ratio=decrease,pad=1080:1080:(ow-iw)/2:(oh-ih)/2:black" \
-c:a copy output_square.mp4
해상도 변경
ffmpeg -y -hide_banner -i input.mp4 -vf "scale=1280:720" -c:a copy output_720p.mp4
압축 (CRF: 18 고품질 ~ 28 작은파일, 23 밸런스)
ffmpeg -y -hide_banner -i input.mp4 \
-c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k output_compressed.mp4
오디오
ffmpeg -y -hide_banner -i input.mp4 -vn -acodec libmp3lame output.mp3
ffmpeg -y -hide_banner -i input.mp4 -vn -acodec pcm_s16le output.wav
ffmpeg -y -hide_banner -i input.mp4 -an -c:v copy output_silent.mp4
속도 조절 (setpts = 1/speed, atempo = speed)
# 2배속
ffmpeg -y -hide_banner -i input.mp4 \
-filter_complex "[0:v]setpts=0.5PTS[v];[0:a]atempo=2.0[a]" \
-map "[v]" -map "[a]" output_2x.mp4
슬로모션 (0.5배속)
ffmpeg -y -hide_banner -i input.mp4 \
-filter_complex "[0:v]setpts=2.0PTS[v];[0:a]atempo=0.5[a]" \
-map "[v]" -map "[a]" output_slow.mp4
회전/플립
ffmpeg -y -hide_banner -i input.mp4 -vf "transpose=1" -c:a copy output_90cw.mp4
ffmpeg -y -hide_banner -i input.mp4 -vf "transpose=2" -c:a copy output_90ccw.mp4
ffmpeg -y -hide_banner -i input.mp4 -vf "hflip" -c:a copy output_mirror.mp4
ffmpeg -y -hide_banner -i input.mp4 -vf "vflip" -c:a copy output_flip.mp4
워터마크
ffmpeg -y -hide_banner -i video.mp4 -i logo.png \
-filter_complex "overlay=W-w-10:10" output_watermarked.mp4
자막
ffmpeg -y -hide_banner -i input.mp4 -vf "subtitles='subs.srt'" output_subtitled.mp4
GIF 변환
ffmpeg -y -hide_banner -i input.mp4 -ss 00:00:10 -t 5 \
-vf "fps=15,scale=480:-1:flags=lanczos" -loop 0 output.gif
썸네일/스크린샷
ffmpeg -y -hide_banner -i input.mp4 -ss 00:01:30 -frames:v 1 screenshot.jpg
병합
# files.txt: file 'v1.mp4'\nfile 'v2.mp4'
ffmpeg -y -hide_banner -f concat -safe 0 -i files.txt -c copy merged.mp4
컬러 스페이스 가이드
| 표준 | 용도 |
|------|------|
| BT.601 | SD 구형 콘텐츠 |
| BT.709 | HD 현대 HD/FHD |
| BT.2020 | UHD/HDR 4K |
| sRGB | Web 웹 배포 |
워크플로우
- 입력 분석 — ffprobe로 비디오 정보 확인
- 작업 계획 — 여러 작업을 단일 패스로 체인할 수 있는지 확인
- 실행 — 스트림 카피 우선, 필요시에만 재인코딩
- 검증 — 출력 파일 확인 (재생, 품질, 길이)
배치 처리 예시
import subprocess, glob
for video in glob.glob("*.mp4"):
output = video.replace(".mp4", "_720p.mp4")
subprocess.run([
"ffmpeg", "-y", "-hide_banner", "-i", video,
"-vf", "scale=1280:720",
"-c:v", "libx264", "-crf", "23", "-preset", "fast",
"-c:a", "copy", output
])