GitHub ↗
CHAPTER 10 OF 10
🛠️

Practical Engineering with ffmpeg

ffmpeg 실전 — 컨테이너·스트리밍·하드웨어

코덱 이론을 손에 잡힌 도구로. 컨테이너 vs 코덱·CRF·하드웨어 인코더·ABR 스트리밍의 실전 매뉴얼.

Practical Engineering with ffmpeg cheatsheet
🍌 NANO BANANA CHEATSHEET · CH 10

Overview

개관

이 코스의 마지막 장. 1~9장의 이론을 실전 도구로 묶는다. ffmpeg가 비디오 엔지니어의 스위스 아미 나이프. 이번 장은 ffmpeg의 주요 사용 패턴 — 트랜스코딩, 컨테이너 변환, 하드웨어 가속, ABR 스트리밍 — 을 매뉴얼처럼 다룬다.

이번 장의 명령들을 외우면 비디오 관련 일상 업무의 90%를 ffmpeg 한 줄로 해결할 수 있다.

🎯 Learning Goals
  • 컨테이너와 코덱을 정확히 구분하고 도메인별 선택 가능
  • ffmpeg의 핵심 명령 5-7개를 외운다
  • 하드웨어 인코더의 trade-off를 안다 (NVENC·VideoToolbox·QSV)
  • HLS·DASH 스트리밍을 ffmpeg로 만들 수 있다
  • Two-pass·multi-bitrate 같은 실전 파이프라인을 이해한다

Sections

본문

10.1 컨테이너 vs 코덱 — 한 번 더 정리

비디오 파일은 두 층으로 구성된다.

컨테이너 (Container): 비디오·오디오·자막·메타데이터를 한 파일로 묶는 봉투. 코덱이 아니라 포맷. - .mp4 (ISO BMFF) — 가장 호환성 좋음. H.264·H.265·AV1·AAC 모두 가능 - .mkv (Matroska) — 거의 모든 코덱 가능. 자막 다국어 잘 다룸 - .webm (서브셋 of Matroska) — VP9·AV1 + Opus 위주. 웹 친화 - .mov (QuickTime) — Apple. ProRes·H.264·H.265 - .ts (MPEG-TS) — 방송·HLS. 스트리밍에 적합

비디오 코덱 (Video Codec): 영상 자체의 압축 방식. H.264·H.265·AV1·VP9·ProRes 등.

오디오 코덱 (Audio Codec): 음향의 압축. AAC·Opus·MP3·FLAC.

.mp4 안에 H.264 + AAC, 또는 H.265 + AAC, 또는 AV1 + Opus 모두 가능. 파일 확장자만 보고 코덱을 추측하면 안 된다. ffprobe로 확인:

``bash ffprobe -v error -show_streams video.mp4 | grep codec_name # codec_name=h264 # codec_name=aac ``

엔지니어가 가장 자주 만지는 컨테이너는 MP4(호환성)TS(스트리밍). 도메인별로 외우면 90% 커버.

10.2 ffmpeg 핵심 명령 — 외워두면 인생 편해짐

ffmpeg의 일상 명령. 외워두면 매일 쓴다.

```bash # 1) 정보 확인 ffprobe -v error -show_format -show_streams input.mp4

# 2) H.264 기본 트랜스코딩 (가장 자주 씀) ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac out.mp4

# 3) H.265로 (절반 크기) ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset medium -c:a aac out.mp4

# 4) 다시 인코딩 없이 컨테이너만 변경 (빠르고 무손실) ffmpeg -i input.mkv -c copy out.mp4

# 5) 해상도 변경 (1080p → 720p) ffmpeg -i input.mp4 -vf scale=1280:720 -c:v libx264 -crf 23 -c:a copy out.mp4

# 6) 일부 잘라내기 (5초~25초) ffmpeg -ss 5 -t 20 -i input.mp4 -c copy clip.mp4

# 7) 키프레임 간격 강제 (스트리밍 준비) ffmpeg -i input.mp4 -c:v libx264 -g 60 -keyint_min 60 -sc_threshold 0 \ -force_key_frames 'expr:gte(t,n_forced*2)' out.mp4

# 8) 오디오만 추출 ffmpeg -i input.mp4 -vn -c:a copy audio.m4a

# 9) GIF로 변환 (작은 클립) ffmpeg -i input.mp4 -vf 'fps=15,scale=480:-1:flags=lanczos' -c:v gif out.gif ```

이 9개가 실무 명령의 80%. 나머지는 자주 안 씀.

10.3 하드웨어 인코더 — NVENC·VideoToolbox·QSV

ffmpeg는 하드웨어 가속 인코더도 지원. CPU 대신 전용 칩(GPU·ASIC)으로 인코딩 → 10~50배 빠름. 단, 화질은 SW 인코더(x264·x265) 보다 약간 떨어짐.

NVIDIA NVENC (RTX/GTX GPU): ``bash ffmpeg -i input.mp4 -c:v h264_nvenc -preset p4 -cq 23 -c:a aac out.mp4 ffmpeg -i input.mp4 -c:v hevc_nvenc -preset p4 -cq 28 -c:a aac out.mp4 ``

Apple VideoToolbox (Mac): ``bash ffmpeg -i input.mp4 -c:v h264_videotoolbox -b:v 4M -c:a aac out.mp4 ffmpeg -i input.mp4 -c:v hevc_videotoolbox -b:v 2M -c:a aac out.mp4 ``

Intel Quick Sync (QSV) (Intel CPU 내장): ``bash ffmpeg -i input.mp4 -c:v h264_qsv -global_quality 23 -c:a aac out.mp4 ``

언제 HW vs SW: - 라이브 스트리밍 (1080p@60 이상) → HW 필수. 5-10% 화질 손해 감수. - 실시간 화상회의 → HW 필수. 저전력 + 짧은 지연. - VOD 라이브러리 (한 번 인코딩 → 영원히 재생) → SW가 정답. 화질 최우선. - 모바일 녹화 → 디바이스 HW가 알아서 (대부분 HEVC HW).

10.4 ABR 스트리밍 — HLS·DASH 만들기

스트리밍 서비스는 여러 비트레이트를 동시에 만들어 클라이언트가 네트워크 상태에 따라 자동 전환 → ABR(Adaptive Bit Rate).

ffmpeg로 HLS 생성:

``bash ffmpeg -i input.mp4 \ -filter_complex '[0:v]split=3[v1][v2][v3]; \ [v1]scale=w=1280:h=720[v1out]; \ [v2]scale=w=854:h=480[v2out]; \ [v3]scale=w=640:h=360[v3out]' \ -map '[v1out]' -c:v:0 libx264 -b:v:0 3M -maxrate:0 3.5M -bufsize:0 6M \ -map '[v2out]' -c:v:1 libx264 -b:v:1 1.5M -maxrate:1 1.8M -bufsize:1 3M \ -map '[v3out]' -c:v:2 libx264 -b:v:2 800k -maxrate:2 1M -bufsize:2 1.6M \ -map a:0 -c:a aac -b:a 128k \ -g 60 -keyint_min 60 -sc_threshold 0 \ -f hls -hls_time 2 -hls_list_size 0 \ -hls_segment_filename 'stream_%v/seg_%03d.ts' \ -master_pl_name master.m3u8 \ -var_stream_map 'v:0,a:0 v:1,a:0 v:2,a:0' \ 'stream_%v/playlist.m3u8' ``

결과: `` master.m3u8 ← 메타: 3개 품질 선택지 stream_0/... ← 720p 3Mbps 세그먼트 stream_1/... ← 480p 1.5Mbps stream_2/... ← 360p 800kbps ``

클라이언트(브라우저 HLS.js, iOS Safari, Android ExoPlayer)가 master.m3u8을 읽고 네트워크 상태에 따라 세 품질을 동적 전환.

핵심 옵션 정리: - -g 60 -keyint_min 60 -sc_threshold 0: 키프레임 일정 간격 (세그먼트 경계 일치) - -hls_time 2: 세그먼트 길이 2초 - -maxrate -bufsize: VBR 캡 — 네트워크 안정성

10.5 Two-pass와 트랜스코딩 파이프라인

Two-pass 인코딩: 1회차에 전체 영상을 분석해 비트레이트 분포를 미리 정한 다음, 2회차에 그 분포대로 인코딩. 목표 평균 비트레이트를 정확히 맞춰야 할 때 사용.

``bash # pass 1 ffmpeg -y -i input.mp4 -c:v libx264 -b:v 2M -pass 1 -an -f null /dev/null # pass 2 ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 2 -c:a aac out.mp4 ``

사용처: 정확한 파일 크기·비트레이트 목표가 있는 다운로드용. CRF로는 파일 크기를 미리 모르는 게 단점인데 two-pass가 해결.

전형적인 프로덕션 트랜스코딩 파이프라인: 1. Ingest: 원본 영상 받음 (보통 ProRes·H.264 고비트레이트) 2. Mezzanine 생성: 후반작업·QC용 중간 인코딩 (H.264 high bitrate) 3. ABR ladder 생성: 360p~4K 5~7단계 비트레이트로 인코딩 (코덱별·해상도별) 4. Segmenting: HLS/DASH로 분할 5. CDN 업로드: 세그먼트를 CDN에 푸시 6. 모니터링: VMAF·viewer drop rate 추적

Netflix·YouTube 같은 회사는 이 파이프라인을 수십 개 코덱 × 수십 개 비트레이트 × 수십 개 해상도 조합으로 운영. 한 영상이 200~300번 인코딩됨.

ffmpeg는 이 파이프라인의 핵심 도구. 직접 운영하든 매니지드 서비스(AWS Elemental·Mux·Cloudflare Stream)를 쓰든 내부는 ffmpeg.

💡 Analogy · 비유
공항의 화물 처리 파이프라인

공항에서 화물을 처리하는 흐름을 보자. (1) 짐 도착 (ingest), (2) X-ray 검사 (QC), (3) 항공기·차량·기차 각각 다른 포장 (multi-bitrate), (4) 컨테이너에 적재 (segmenting), (5) 운송 (CDN 업로드), (6) 도착지에서 모니터링.

각 단계가 비디오 트랜스코딩 파이프라인과 정확히 매핑된다. 그리고 컨테이너의 의미도 분명해진다 — 한 화물(영상)을 어떤 봉투(MP4·TS)에 담을지는 도착지(클라이언트)에 따라 다르다.

하드웨어 인코더는 "전용 화물 처리기". CPU(범용 직원)가 한 박스 포장하는 데 10분이면, 전용 기계는 30초. 화질이 살짝 떨어지지만 처리량 폭증.

ABR 스트리밍은 "고객 차량에 따라 다른 크기 박스 자동 선택". 작은 차에는 작은 박스(360p), 큰 트럭에는 큰 박스(4K). 클라이언트가 자기 능력을 보고 자동 선택.

Python으로 ffmpeg를 wrapping해서 ABR ladder를 자동 생성하는 미니 파이프라인. 실제 프로덕션에서 자주 쓰는 패턴.

python
import subprocess
from pathlib import Path

def generate_abr_ladder(input_path, output_dir, codec='h264'):
    """Generate HLS multi-bitrate ladder."""
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)

    # ABR ladder: (height, bitrate Kbps)
    ladder = [
        (360,   800),
        (480,  1500),
        (720,  3000),
        (1080, 5000),
    ]

    lib = {'h264': 'libx264', 'h265': 'libx265', 'av1': 'libsvtav1'}[codec]

    # Build the filter complex
    split = f'[0:v]split={len(ladder)}'
    splits = ''.join(f'[v{i}]' for i in range(len(ladder)))
    scales = ';'.join(
        f'[v{i}]scale=-2:{h}[v{i}out]'
        for i, (h, _) in enumerate(ladder)
    )
    filter_complex = f'{split}{splits}; {scales}'

    cmd = ['ffmpeg', '-y', '-i', str(input_path),
           '-filter_complex', filter_complex]

    for i, (h, b) in enumerate(ladder):
        cmd += ['-map', f'[v{i}out]',
                f'-c:v:{i}', lib,
                f'-b:v:{i}', f'{b}k',
                f'-maxrate:{i}', f'{int(b*1.2)}k',
                f'-bufsize:{i}', f'{b*2}k']

    cmd += ['-map', 'a:0', '-c:a', 'aac', '-b:a', '128k',
            '-g', '60', '-keyint_min', '60', '-sc_threshold', '0',
            '-f', 'hls', '-hls_time', '2', '-hls_list_size', '0',
            '-hls_segment_filename', f'{output_dir}/v%v/s%03d.ts',
            '-master_pl_name', 'master.m3u8',
            '-var_stream_map',
            ' '.join(f'v:{i},a:0' for i in range(len(ladder))),
            f'{output_dir}/v%v/playlist.m3u8']

    print('Running:', ' '.join(cmd[:8]), '...')
    subprocess.run(cmd, check=True)
    print(f'✓ ABR ladder ready at {output_dir}/master.m3u8')

# Usage
generate_abr_ladder('input.mp4', 'hls_out', codec='h264')
# Output:
# hls_out/
#   master.m3u8        ← 클라이언트 진입점
#   v0/playlist.m3u8 + s001.ts ... (360p 800k)
#   v1/playlist.m3u8 + s001.ts ... (480p 1.5M)
#   v2/playlist.m3u8 + s001.ts ... (720p 3M)
#   v3/playlist.m3u8 + s001.ts ... (1080p 5M)

이 함수가 프로덕션 ABR 파이프라인의 미니어처. 입력 영상 하나에서 4단계 비트레이트의 HLS 세트를 생성. 클라이언트(웹·iOS·Android)가 master.m3u8을 받아 네트워크 상태에 따라 자동으로 품질 전환. 실제 대형 서비스는 이 ladder를 7~10단계로 늘리고, H.264·H.265·AV1 세 코덱 다 만들어서 디바이스별 fallback까지 처리한다.

🏭 현업에서의 평가
ffmpeg를 손에 잡힌 도구로 만드는 게 비디오 엔지니어의 최소 자질. 면접에서 'ffmpeg 명령 즉답' + 'ABR 구조 이해'를 본다.

✅ 시니어가 보는 것

  • 컨테이너·코덱 구분과 ffprobe로 검증 가능
  • ffmpeg 일상 명령 5-7개 외우고 있음
  • HW vs SW 인코더의 trade-off 도메인별로 판단
  • HLS/DASH ABR ladder 설계 가능
  • Two-pass·single-pass 선택 기준 안다

⚠️ 레드 플래그

  • MP4가 코덱이라고 답함
  • 라이브에 x265 preset slow 쓰려고 함
  • 키프레임 간격을 세그먼트 길이와 안 맞춰 HLS 깨뜨림
  • ABR ladder를 7-10단계가 아니라 1-2단계만 만듦

🎤 예상 인터뷰 질문

  1. HLS와 DASH의 차이와 사용 사례를 설명해 주세요
  2. NVENC vs x264의 trade-off는?
  3. ABR ladder 설계 시 고려할 요소를 5가지 말해 주세요
숙달 vs 익숙함: Familiar는 'ffmpeg로 인코딩한다'를 안다. Mastery는 컨테이너·코덱·해상도·비트레이트·키프레임·세그먼트·CDN까지 통합적으로 설계하고, ffmpeg 명령으로 직접 구현하며, HW·SW 인코더를 도메인별로 선택한다.

Key Takeaways

핵심 정리

컨테이너 ≠ 코덱

MP4 안에 H.264·H.265·AV1 다 가능.

ffprobe로 확인

확장자만 보고 추측 X.

9개 명령 외우기

일상 업무의 80%를 커버.

Stream copy

-c copy로 무인코딩 컨테이너 변환.

HW 인코더

10-50배 빠름, 화질 약간 손해. 라이브 필수.

ABR ladder

여러 비트레이트 동시 생성. ABR 스트리밍의 기본.

HLS = 2초 세그먼트 + 일정 키프레임

둘 안 맞추면 깨짐.

Two-pass

정확한 비트레이트 목표 시. CRF는 크기 예측 불가.