영상 인코딩 도구 고르기: ffmpeg preset과 faststart 실행 결과, GStreamer와의 역할 차이

이 글의 핵심

8초 720p 합성 영상을 libx264 crf 23으로 인코딩했을 때 preset ultrafast는 0.24초에 7.5MB, medium은 0.72초에 3.1MB, slow는 1.27초에 3.0MB였습니다. faststart를 켜면 MP4의 moov 박스가 mdat 앞으로 이동했습니다. 이 결과와 ffmpeg·GStreamer의 역할 차이를 정리했습니다.

영상 파일을 다룰 때 처음 만나는 도구는 ffmpeg와 GStreamer다. 둘 다 인코딩과 변환을 하지만 쓰임새가 다르다. 이 글은 ffmpeg에서 가장 많이 만지는 preset과 faststart를 실제로 실행해 보고, 두 도구의 역할 차이를 정리한다. 환경은 ffmpeg 9.0.2(Homebrew), macOS arm64이고, 입력은 testsrc2 합성 영상(1280x720, 30fps, 8초)이다. 합성 영상은 움직임과 질감이 실제 촬영 영상과 다르므로 숫자는 경향을 보는 용도다.

실행 결과

ffmpeg -f lavfi -i testsrc2=size=1280x720:rate=30 -t 8 \
  -c:v libx264 -preset <이름> -crf 23 -pix_fmt yuv420p out.mp4
preset인코딩 시간파일 크기
ultrafast0.24초7,499,196바이트
medium0.72초3,137,487바이트
slow1.27초3,027,167바이트
  • ultrafast는 빠르지만 같은 crf 값에서 파일이 medium의 약 2.4배였다.
  • medium에서 slow로 가면 시간이 약 1.8배 걸리고 크기는 약 3.5% 줄었다. 이 이득이 시간을 들일 만한지는 용도에 따른다.
  • 각 preset을 한 번씩만 실행한 값이라 오차가 있다.

화질(VMAF)까지 포함한 비교, crf 값별 변화, 실제 영상 기준의 폭은 ffmpeg libx264 실험: preset과 crf에서 다룬다.

faststart가 바꾸는 것

MP4 파일은 moov(재생 정보)와 mdat(실제 데이터) 박스로 이뤄지는데, 기본 인코딩 결과는 moov가 파일 끝에 있다. 웹에서 재생하려면 moov를 먼저 받아야 하므로 앞으로 옮기는 옵션이 -movflags +faststart다. 같은 파일에 ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4를 적용하자 박스 순서가 다음처럼 바뀌었다.

파일앞쪽 박스 순서
기본 인코딩ftyp, free, mdat, moov
faststart 적용ftyp, moov, free, mdat

-c copy는 다시 인코딩하지 않고 컨테이너만 다시 쓰므로 빠르다. 이 박스 순서 확인은 ffmpeg를 쓰지 않고 브라우저에서 영상을 처리하는 도구를 만들 때도 같은 이유로 테스트했다.

crf를 바꾸면 크기와 화질이 얼마나 변하나

같은 합성 영상(testsrc2, 720p, 30fps, 8초)을 libx264 -preset medium으로 crf만 바꿔 인코딩하고, 원본과 비교한 VMAF 점수(ffmpeg의 libvmaf 필터)도 같이 구했다.

crf인코딩 시간파일 크기VMAF
180.76초4,834,394바이트98.67
230.66초3,137,487바이트97.16
280.61초1,531,244바이트93.72
350.52초712,101바이트84.69
  • crf를 5 올릴 때마다 크기가 대략 절반에 가깝게 줄었다(23→28에서 약 51%, 28→35에서는 약 53%). 이 합성 영상에서의 경향이다.
  • VMAF는 crf 18에서 23으로 가면 1.5점, 28에서 35로 가면 9점이 떨어졌다. 화질이 급격히 나빠지는 구간은 crf가 큰 쪽에 있었다.
  • 합성 영상은 반복되는 무늬와 단순한 움직임이라 실제 촬영 영상보다 압축이 잘 된다. 같은 crf라도 실제 영상에서는 크기가 훨씬 크고 VMAF 변화 폭도 다를 수 있으므로, 이 표는 “crf가 이런 방향으로 작용한다”는 확인으로만 쓴다.

하드웨어 인코더와 소프트웨어 인코더

이 맥의 ffmpeg는 h264_videotoolbox(애플의 하드웨어 H.264 인코더)를 지원했다. 같은 입력을 -b:v 3M으로 인코딩했다.

인코더설정시간크기
libx264crf 23, medium0.66초3,137,487바이트
h264_videotoolbox비트레이트 3Mbps0.79초3,050,422바이트

이 8초짜리 합성 영상에서는 하드웨어 인코더가 더 빠르지 않았다. 입력이 짧고 단순해서 시작 비용이 지배적일 수 있다. 긴 영상과 실제 촬영 영상에서의 속도와 화질은 확인하지 않았다. 하드웨어 인코더는 보통 같은 비트레이트에서 소프트웨어 인코더(libx264의 느린 preset)보다 압축 효율이 낮다고 알려져 있으나 이 글에서 비교하지 않았다.

컨테이너만 바꿀 때와 다시 인코딩할 때

작업시간결과
-c copy로 컨테이너만 다시 쓰기0.05초같은 영상·음성 데이터를 그대로 복사
720p → 360p로 줄이면서 재인코딩(-vf scale=640:360, crf 23)0.29초397,378바이트

형식만 바꾸거나 faststart 위치만 옮길 때는 -c copy가 훨씬 빠르고 화질 손실이 없다. 해상도를 바꾸려면 재인코딩이 필요하다. 이 글의 8초 영상에서 해상도를 절반으로 줄이자 크기가 약 8분의 1이 됐다(3.1MB → 0.4MB).

결과를 확인하는 방법: ffprobe

인코딩 결과가 의도대로인지는 ffprobe로 읽는다.

ffprobe -v error -select_streams v:0 \
  -show_entries stream=codec_name,width,height,r_frame_rate,bit_rate \
  -show_entries format=duration,size -of default=nw=1 out.mp4

위 파일에서는 codec_name=h264, width=1280, height=720, r_frame_rate=30/1, bit_rate=3133996, duration=8.000000, size=3137487이 나왔다. 비트레이트와 크기, 길이가 서로 맞는지(3,137,487바이트×8÷8초 ≈ 3.14Mbps) 계산으로 확인하면 파일이 잘못 만들어졌는지 알 수 있다.

ffmpeg와 GStreamer: 역할 차이

구분ffmpegGStreamer
중심파일 변환·인코딩 명령 한 줄소스, 필터, 싱크를 이어 붙이는 파이프라인
잘 맞는 일포맷 변환, 인코딩 옵션 실험, 일괄 처리카메라·네트워크 스트림을 실시간으로 받아 처리
배우는 방식옵션과 필터요소(element)와 패드 연결

이 표는 일반적으로 알려진 역할 구분이고, 이 글에서 GStreamer는 실행하지 않았다(gst-launch를 설치하지 않았다). GStreamer의 요소 조립과 C·파이썬 연동은 GStreamer 실전 가이드에 정리했다. 코덱과 컨테이너의 배경 지식은 H.264 가이드와 MP4 컨테이너 가이드를 참고한다.

고르는 기준

  • 파일을 바꾸고 옵션을 비교한다: ffmpeg.
  • 카메라나 네트워크 스트림을 실시간으로 이어 붙인다: GStreamer 쪽을 먼저 검토한다.
  • 웹 재생용 MP4를 만든다: -movflags +faststart를 확인한다.

확인하지 못한 것

  • 실제 촬영 영상과 다른 해상도에서의 preset 효과.
  • 하드웨어 인코더(VideoToolbox, NVENC)와의 비교.
  • GStreamer 파이프라인의 실행 결과.