FFmpeg Essentials
항상 먼저 프로브하고, 입력 파일을 덮어쓰지 않으며, 명시적으로 지시하지 않는 한 자를 때는 다시 인코딩합니다.
프로브
# 사람이 읽기 쉬운 요약
ffprobe -v error -show_entries stream=codec_type,codec_name,width,height,r_frame_rate,sample_rate -show_entries format=duration,size -of default=nw=1 input.mp4
# 기계가 읽기 쉬운 형식
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4
자르기
# 30초부터 시작하여 15초 유지. 다시 인코딩: 정확하고 안전합니다.
ffmpeg -i input.mp4 -ss 00:00:30 -t 15 -c:v libx264 -crf 20 -c:a aac out/clip.mp4
# 빠르게, 재인코딩 없음. 키프레임에만 맞춰지므로 시작점이 몇 초 정도 차이날 수 있습니다.
ffmpeg -ss 00:00:30 -i input.mp4 -t 15 -c copy out/clip.mp4
-ss를 -i 앞에 두면 빠르게 탐색합니다. -i 뒤에 두면 정확하지만 느립니다. 재인코딩의 경우 최신 FFmpeg에서는 둘 다 괜찮습니다.
합치기
# 동일한 코덱, 해상도, 프레임 속도: 즉시, 무손실
printf "file 'a.mp4'\nfile 'b.mp4'\n" > list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy out/joined.mp4
# 다른 소스: 합치면서 정규화
ffmpeg -i a.mp4 -i b.mp4 -filter_complex \
"[0:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,fps=30,setsar=1[v0];\
[1:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,fps=30,setsar=1[v1];\
[0:a][1:a]concat=n=2:v=1:a=1[v][a]" \
-map "[v]" -map "[a]" -c:v libx264 -crf 20 -c:a aac out/joined.mp4
PowerShell: Set-Content를 사용하여 list.txt를 작성하고, \ 대신 백틱 줄 연속 또는 한 줄로 작성합니다.
크기 조정 및 프레임 재구성
# 1920x1080 내부에 맞추고 막대 추가
-vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2"
# 1920x1080 채우기, 넘치는 부분 자르기
-vf "scale=1920:1080:force_original_aspect_ratio=increase,crop=1920:1080"
# 너비 1280, 높이 자동 및 짝수
-vf "scale=1280:-2"
압축
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k -movflags +faststart out/small.mp4
| 목적 | CRF | 프리셋 |
|---|---|---|
| 마스터 / 아카이브 | 16-18 | slow |
| 프로덕션 | 20-22 | medium |
| 웹 / 미리보기 | 23-26 | fast |
| 빠른 초안 | 28+ | veryfast |
CRF가 낮을수록 품질이 높아지고 파일 크기가 커집니다. 대상 크기가 있는 경우 CRF 대신 2패스 -b:v를 사용하세요.
속도
# 2배 빠르게, 비디오 및 오디오
ffmpeg -i in.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" out/fast.mp4
# 0.5배 슬로우 모션
ffmpeg -i in.mp4 -filter_complex "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]" -map "[v]" -map "[a]" out/slow.mp4
# 비디오 전용
ffmpeg -i in.mp4 -an -filter:v "setpts=0.25*PTS" out/timelapse.mp4
setpts 배율 = 1 / 속도. atempo는 필터당 0.5에서 2.0까지 허용하므로, 더 높은 속도를 위해 체인으로 연결할 수 있습니다: atempo=2.0,atempo=2.0으로 4배속.
페이드
# 10초 클립에 1초 인, 1초 아웃
ffmpeg -i in.mp4 -vf "fade=t=in:st=0:d=1,fade=t=out:st=9:d=1" -af "afade=t=in:st=0:d=1,afade=t=out:st=9:d=1" out/faded.mp4
오디오
ffmpeg -i in.mp4 -vn -c:a libmp3lame -q:a 2 out/audio.mp3 # mp3 추출
ffmpeg -i in.mp4 -vn -c:a copy out/audio.m4a # 재인코딩 없이 추출 (AAC 소스)
ffmpeg -i video.mp4 -i voice.wav -map 0:v -map 1:a -c:v copy -c:a aac -shortest out/dubbed.mp4 # 오디오 교체
ffmpeg -i in.mp4 -an -c:v copy out/silent.mp4 # 오디오 제거
GIF
ffmpeg -i in.mp4 -t 5 -vf "fps=15,scale=480:-1:flags=lanczos,split[a][b];[a]palettegen[p];[b][p]paletteuse" out/preview.gif
이미지
ffmpeg -ss 5 -i in.mp4 -frames:v 1 -q:v 2 out/frame.jpg # 한 프레임
ffmpeg -framerate 30 -i frames/%04d.png -c:v libx264 -pix_fmt yuv420p out/from-frames.mp4
ffmpeg -loop 1 -i still.png -t 5 -c:v libx264 -pix_fmt yuv420p -r 30 out/still.mp4
문제 해결
| 증상 | 해결책 |
|---|---|
height not divisible by 2 | scale=trunc(iw/2)*2:trunc(ih/2)*2 추가 |
| VLC에서는 재생되지만 브라우저나 휴대폰에서는 안 됨 | -c:v libx264 -pix_fmt yuv420p -movflags +faststart |
| 속도 변경 후 오디오 드리프트 | filter_complex에서 setpts와 atempo를 함께 사용 |
| 가변 프레임 속도 휴대폰 클립에서 오디오 드리프트 | -vsync cfr -r 30 (또는 -fps_mode cfr) 추가 |
-c copy 자르기 후 첫 프레임 검은색 | 스트림 복사 대신 재인코딩 |
| 출력 파일이 0바이트 | -v error로 전체 오류 확인; 스트림 매핑 확인 |
| 경로에 공백 포함 | 따옴표로 묶기: "my clip.mp4" |
| 덮어쓰기 확인으로 자동화 차단 | -y(덮어쓰기) 또는 -n(안 함) 추가 |
안전 습관
out/폴더에 쓰고, 입력 경로에 절대 쓰지 않습니다.- 스크립트에서
-hide_banner -loglevel error를 추가하고, 진행 상황을 보려면-stats를 추가합니다. ffprobe와video-qa스킬로 결과를 확인합니다.