H.264 코덱 완벽 가이드 | NAL·SPS·PPS·프로파일·레벨 심층 분석

H.264 코덱 완벽 가이드 | NAL·SPS·PPS·프로파일·레벨 심층 분석

이 글의 핵심

H.264 코덱 완벽 가이드. NAL Unit, SPS, PPS 구조부터 프로파일, 레벨, 비트스트림 분석, 실전 인코딩까지 기초부터 실무까지 완벽 정리.

들어가며

H.264 (AVC, MPEG-4 Part 10)가장 널리 사용되는 비디오 코덱입니다. YouTube, Netflix, Zoom 등 대부분의 영상 서비스가 H.264를 사용합니다.

비유로 말씀드리면, H.264영상 압축의 만능 열쇠입니다. H.265가 더 효율적이지만, H.264모든 기기에서 작동하고 특허 문제가 없어 여전히 표준입니다.

이 글을 읽으면

  • H.264의 구조와 원리를 이해합니다
  • NAL Unit, SPS, PPS 등 헤더 정보를 파악합니다
  • 프로파일과 레벨을 선택할 수 있습니다
  • 실전 인코딩과 디코딩을 구현합니다

목차

  1. H.264 기초
  2. NAL Unit 구조
  3. SPS (Sequence Parameter Set)
  4. PPS (Picture Parameter Set)
  5. Slice와 Macroblock
  6. 프로파일과 레벨
  7. 비트스트림 분석
  8. 실전 인코딩
  9. 왜 아직도 H.264인가
  10. 트러블슈팅
  11. 마무리

H.264 기초

H.264란?

H.264 (Advanced Video Coding)는 2003년 ITU-T와 ISO/IEC가 공동 개발한 비디오 압축 표준입니다.

별칭:

  • H.264 (ITU-T 명칭)
  • AVC (Advanced Video Coding)
  • MPEG-4 Part 10

H.264의 압축 원리

1. 공간적 중복 제거 (Intra Prediction)

원본 프레임:
■■■■■■■■
■■■■■■■■
■■■■■■■■

인접 픽셀이 비슷함 → 차이만 저장
→ 압축!

2. 시간적 중복 제거 (Inter Prediction)

프레임 1: 공이 왼쪽에
프레임 2: 공이 오른쪽으로 이동

전체 프레임 저장 X
→ "공이 오른쪽으로 10픽셀 이동" 만 저장
→ 압축!

3. 변환 및 양자화 (DCT + Quantization)

픽셀 값 → 주파수 변환 (DCT)
→ 중요하지 않은 고주파 제거 (Quantization)
→ 압축!

H.264 프레임 타입

I-Frame (Intra Frame)

  • 독립적인 완전한 프레임
  • 압축률 낮음, 용량 큼
  • 시크(Seek) 포인트

P-Frame (Predicted Frame)

  • 이전 프레임 참조
  • 압축률 중간
  • I-Frame보다 작음

B-Frame (Bi-directional Frame)

  • 이전 + 이후 프레임 참조
  • 압축률 높음, 용량 작음
  • 인코딩 복잡
GOP (Group of Pictures):
I P P P P P P P I P P P P P P P

I: 키프레임 (독립적)
P: 이전 프레임 참조
B: 양방향 참조 (선택적)

NAL Unit 구조

NAL Unit이란?

NAL (Network Abstraction Layer) Unit은 H.264 비트스트림의 기본 단위입니다.

구조:

[Start Code] [NAL Header] [NAL Payload]
   3-4 bytes     1 byte      가변 길이

Start Code

Annex B 포맷:

0x00 0x00 0x00 0x01  (4 bytes, 일반적)
또는
0x00 0x00 0x01       (3 bytes, 짧은 형식)

AVCC 포맷 (MP4):

[Length] [NAL Data]
4 bytes   가변 길이

Length: NAL Unit 크기 (빅 엔디안)

NAL Header (1 byte)

 7 6 5 4 3 2 1 0
┌─┬─────┬─────────┐
│F│ NRI │  Type   │
└─┴─────┴─────────┘

F (Forbidden Zero Bit): 항상 0
NRI (NAL Ref IDC): 중요도 (0-3)
Type (NAL Unit Type): NAL 타입 (0-31)

NAL Unit 타입

타입이름설명
0Unspecified미정의
1Coded Slice (Non-IDR)P/B 프레임 슬라이스
2Coded Slice (Partition A)데이터 분할 A
3Coded Slice (Partition B)데이터 분할 B
4Coded Slice (Partition C)데이터 분할 C
5Coded Slice (IDR)I 프레임 (키프레임)
6SEI (Supplemental Enhancement)부가 정보
7SPS시퀀스 파라미터 세트
8PPS픽처 파라미터 세트
9Access Unit DelimiterAU 구분자
10End of Sequence시퀀스 종료
11End of Stream스트림 종료
12Filler Data채우기 데이터

예시:

0x67: NAL Type 7 (SPS)
  Binary: 0110 0111
  F: 0
  NRI: 11 (중요도 3, 최고)
  Type: 00111 (7, SPS)

0x68: NAL Type 8 (PPS)
  Binary: 0110 1000
  F: 0
  NRI: 11 (중요도 3)
  Type: 01000 (8, PPS)

0x65: NAL Type 5 (IDR)
  Binary: 0110 0101
  F: 0
  NRI: 11 (중요도 3)
  Type: 00101 (5, IDR 프레임)

0x41: NAL Type 1 (Non-IDR)
  Binary: 0100 0001
  F: 0
  NRI: 10 (중요도 2)
  Type: 00001 (1, P/B 프레임)

SPS (Sequence Parameter Set)

SPS란?

SPS전체 비디오 시퀀스의 설정을 담고 있습니다. 디코더가 영상을 해석하는 데 필수적입니다.

포함 정보:

  • 프로파일 (Profile)
  • 레벨 (Level)
  • 해상도 (Width, Height)
  • 프레임 레이트
  • 색상 정보
  • 비트 깊이

SPS 구조

SPS NAL Unit:
[Start Code] [NAL Header (0x67)] [SPS Data]

SPS Data (비트 단위):
- profile_idc (8 bits)
- constraint_set_flags (8 bits)
- level_idc (8 bits)
- seq_parameter_set_id (ue(v))
- chroma_format_idc (ue(v))
- bit_depth_luma_minus8 (ue(v))
- bit_depth_chroma_minus8 (ue(v))
- log2_max_frame_num_minus4 (ue(v))
- pic_order_cnt_type (ue(v))
- max_num_ref_frames (ue(v))
- pic_width_in_mbs_minus1 (ue(v))
- pic_height_in_map_units_minus1 (ue(v))
- frame_mbs_only_flag (1 bit)
- ...

ue(v): Exp-Golomb 가변 길이 인코딩

SPS 예시 분석

SPS 바이트:

00 00 00 01 67 64 00 1F AC D9 40 50 05 BB 01 6A 02 02 02 80 00 00 03 00 80 00 00 19 47 8C 18 CB

분석:

00 00 00 01: Start Code
67: NAL Header (Type 7, SPS)

64: profile_idc = 100 (High Profile)
00: constraint_set_flags
1F: level_idc = 31 (Level 3.1)

AC D9 40 50 05 BB 01 6A 02 02 02 80 ...
→ 비트 단위로 파싱:

seq_parameter_set_id = 0
chroma_format_idc = 1 (4:2:0)
bit_depth_luma_minus8 = 0 (8-bit)
bit_depth_chroma_minus8 = 0 (8-bit)
log2_max_frame_num_minus4 = 0 (max_frame_num = 16)
pic_order_cnt_type = 0
max_num_ref_frames = 4
pic_width_in_mbs_minus1 = 79 (width = 1280)
pic_height_in_map_units_minus1 = 44 (height = 720)

SPS 추출 (FFmpeg)

# SPS/PPS 추출
ffmpeg -i input.mp4 -c copy -bsf:v h264_mp4toannexb -f h264 - | \
  xxd | head -50

# 또는 MediaInfo로 확인
mediainfo input.mp4 --Details=1

PPS (Picture Parameter Set)

PPS란?

PPS각 픽처(프레임)의 설정을 담고 있습니다. SPS보다 자주 변경될 수 있습니다.

포함 정보:

  • Entropy 코딩 모드 (CAVLC/CABAC)
  • 슬라이스 그룹 정보
  • 양자화 파라미터
  • 디블로킹 필터 설정

PPS 구조

PPS NAL Unit:
[Start Code] [NAL Header (0x68)] [PPS Data]

PPS Data:
- pic_parameter_set_id (ue(v))
- seq_parameter_set_id (ue(v))
- entropy_coding_mode_flag (1 bit)
  → 0: CAVLC, 1: CABAC
- pic_order_present_flag (1 bit)
- num_slice_groups_minus1 (ue(v))
- num_ref_idx_l0_active_minus1 (ue(v))
- num_ref_idx_l1_active_minus1 (ue(v))
- weighted_pred_flag (1 bit)
- weighted_bipred_idc (2 bits)
- pic_init_qp_minus26 (se(v))
- deblocking_filter_control_present_flag (1 bit)
- ...

PPS 예시

00 00 00 01 68 EE 3C 80

00 00 00 01: Start Code
68: NAL Header (Type 8, PPS)

EE 3C 80:
→ 비트 단위 파싱:

pic_parameter_set_id = 0
seq_parameter_set_id = 0
entropy_coding_mode_flag = 1 (CABAC)
pic_order_present_flag = 0
num_slice_groups_minus1 = 0
num_ref_idx_l0_active_minus1 = 3
num_ref_idx_l1_active_minus1 = 1
weighted_pred_flag = 0
weighted_bipred_idc = 0
pic_init_qp_minus26 = 0 (QP = 26)
deblocking_filter_control_present_flag = 1

Slice와 Macroblock

Slice란?

Slice는 프레임을 독립적으로 디코딩 가능한 단위로 나눈 것입니다.

Slice 타입:

타입이름설명
IIntra SliceI-Frame (독립적)
PPredicted SliceP-Frame (이전 참조)
BBi-directional SliceB-Frame (양방향 참조)
SISwitching I스위칭용 I
SPSwitching P스위칭용 P

Slice 구조

Slice NAL Unit:
[Start Code] [NAL Header] [Slice Header] [Slice Data]

Slice Header:
- first_mb_in_slice (ue(v))
- slice_type (ue(v))
- pic_parameter_set_id (ue(v))
- frame_num (u(v))
- pic_order_cnt_lsb (u(v))
- ...

Slice Data:
- Macroblock 1
- Macroblock 2
- ...

Macroblock이란?

Macroblock16×16 픽셀 블록으로, H.264의 기본 처리 단위입니다.

프레임 (1920×1080):
→ 120 × 68 = 8,160개의 Macroblock

각 Macroblock:
- 16×16 Luma (Y)
- 8×8 Chroma (Cb, Cr) × 2

Macroblock 파티션:

16×16 (전체)
┌────────────────┐
│                │
│                │
│                │
│                │
└────────────────┘

16×8 (상하 분할)
┌────────────────┐
│                │
├────────────────┤
│                │
└────────────────┘

8×16 (좌우 분할)
┌────────┬───────┐
│        │       │
│        │       │
│        │       │
│        │       │
└────────┴───────┘

8×8 (4분할)
┌────────┬───────┐
│        │       │
├────────┼───────┤
│        │       │
└────────┴───────┘

프로파일과 레벨

프로파일 (Profile)

프로파일사용 가능한 기능의 집합입니다.

주요 프로파일:

프로파일profile_idc특징용도
Baseline66B-Frame 없음, CAVLC모바일, 화상 통화
Main77B-Frame, CABAC방송, 스트리밍
High1008×8 변환, 양자화Blu-ray, HDTV
High 1011010-bit전문가용
High 4:2:21224:2:2 색상방송 스튜디오
High 4:4:42444:4:4 색상, 무손실전문가용

프로파일 선택:

모바일/WebRTC: Baseline
YouTube/Netflix: Main 또는 High
Blu-ray: High
전문가: High 10 이상

레벨 (Level)

레벨해상도, 프레임 레이트, 비트레이트 제한을 정의합니다.

주요 레벨:

레벨level_idc최대 해상도최대 fps최대 비트레이트
3.030720×5763010 Mbps
3.1311280×7203014 Mbps
4.0401920×10803020 Mbps
4.1411920×10803050 Mbps
5.0502560×192030135 Mbps
5.1513840×2160 (4K)30240 Mbps
5.2524096×2160 (4K)60240 Mbps

레벨 계산:

MacroBlocks per Second (MBPS):
= (Width / 16) × (Height / 16) × FPS

예시: 1920×1080 @ 30fps
= (1920/16) × (1080/16) × 30
= 120 × 68 × 30
= 244,800 MBPS

Level 4.0: 최대 245,760 MBPS
→ 1920×1080 @ 30fps 가능!

비트스트림 분석

실제 H.264 비트스트림 예시

00 00 00 01 67 64 00 1F AC D9 40 50 05 BB 01 6A  [email protected]
00 00 00 01 68 EE 3C 80                          ....h.<.
00 00 00 01 65 88 84 00 ...                      ....e...
00 00 00 01 41 9A 21 ...                         ....A.!.

분석:

1. SPS (00 00 00 01 67 ...)
   - Start Code: 00 00 00 01
   - NAL Header: 67 (Type 7)
   - Profile: High (100)
   - Level: 3.1
   - 해상도: 1280×720

2. PPS (00 00 00 01 68 ...)
   - Start Code: 00 00 00 01
   - NAL Header: 68 (Type 8)
   - Entropy: CABAC

3. IDR Frame (00 00 00 01 65 ...)
   - Start Code: 00 00 00 01
   - NAL Header: 65 (Type 5, IDR)
   - I-Frame 데이터

4. P Frame (00 00 00 01 41 ...)
   - Start Code: 00 00 00 01
   - NAL Header: 41 (Type 1, Non-IDR)
   - P-Frame 데이터

비트스트림 분석 도구

1. FFmpeg:

# NAL Unit 정보 출력
ffmpeg -i input.mp4 -c copy -bsf:v trace_headers -f null - 2>&1 | grep -A 10 "nal_unit_type"

# 상세 분석
ffprobe -show_packets -show_data -print_format json input.mp4 > analysis.json

2. H264Naked (Python):

from h264_naked import H264Parser

parser = H264Parser()
with open('video.h264', 'rb') as f:
    data = f.read()
    
for nal in parser.parse(data):
    print(f"NAL Type: {nal.type}")
    print(f"Size: {nal.size}")
    if nal.type == 7:  # SPS
        print(f"Profile: {nal.profile}")
        print(f"Level: {nal.level}")
        print(f"Width: {nal.width}")
        print(f"Height: {nal.height}")

3. MediaInfo:

mediainfo input.mp4 --Details=1 | grep -A 20 "Video"

실전 인코딩

FFmpeg로 H.264 인코딩

기본 인코딩:

ffmpeg -i input.mp4 \
       -c:v libx264 \
       -crf 23 \
       -preset medium \
       -c:a aac -b:a 128k \
       output.mp4

프로파일과 레벨 지정:

ffmpeg -i input.mp4 \
       -c:v libx264 \
       -profile:v high \
       -level 4.1 \
       -crf 23 \
       -preset medium \
       output.mp4

고급 설정:

ffmpeg -i input.mp4 \
       -c:v libx264 \
       -profile:v high \
       -level 4.1 \
       -crf 23 \
       -preset slow \
       -tune film \
       -x264-params "keyint=60:min-keyint=30:scenecut=40:ref=4:bframes=3:b-adapt=2:me=umh:subme=8:trellis=2:aq-mode=3" \
       -c:a aac -b:a 192k \
       output.mp4

# 설명:
# keyint=60: GOP 크기 (2초 @ 30fps)
# min-keyint=30: 최소 GOP 크기
# scenecut=40: 장면 전환 감지
# ref=4: 참조 프레임 수
# bframes=3: B-Frame 수
# b-adapt=2: 적응형 B-Frame
# me=umh: 움직임 추정 알고리즘
# subme=8: 서브픽셀 정밀도
# trellis=2: Trellis 양자화
# aq-mode=3: 적응형 양자화

프리셋 비교

프리셋속도품질파일 크기용도
ultrafast매우 빠름낮음실시간 스트리밍
superfast빠름낮음라이브
veryfast빠름중간중간일반 스트리밍
faster빠름중간중간일반
fast보통좋음중간일반
medium보통좋음작음기본값
slow느림매우 좋음작음VOD
slower매우 느림최고매우 작음아카이브
veryslow극도로 느림최고매우 작음전문가

CRF (Constant Rate Factor)

CRF품질 기반 인코딩입니다.

CRF 값:
0  = 무손실 (매우 큼)
18 = 시각적 무손실
23 = 기본값 (권장)
28 = 낮은 품질
51 = 최악의 품질

권장:
애니메이션: CRF 15-20
영화: CRF 18-24
웹 비디오: CRF 23-28

2-Pass 인코딩

더 나은 품질을 위한 2단계 인코딩:

# Pass 1: 분석
ffmpeg -i input.mp4 \
       -c:v libx264 \
       -b:v 5M \
       -pass 1 \
       -f null /dev/null

# Pass 2: 인코딩
ffmpeg -i input.mp4 \
       -c:v libx264 \
       -b:v 5M \
       -pass 2 \
       -c:a aac -b:a 192k \
       output.mp4

왜 아직도 H.264인가

H.264 vs H.265 (HEVC)

특성H.264H.265
압축률기준50% 더 효율적
인코딩 속도빠름느림 (10배)
디코딩 부하낮음높음
하드웨어 지원모든 기기최신 기기만
브라우저 지원100%제한적
특허만료 (무료)복잡 (유료)
파일 크기기준50% 작음

H.264를 선택하는 이유

1. 범용성

H.264 지원:
- 모든 스마트폰 (iPhone 3GS 이후)
- 모든 브라우저
- 모든 스마트 TV
- 모든 게임 콘솔
- 모든 카메라

H.265 지원:
- 최신 스마트폰만
- 일부 브라우저 (Safari만)
- 최신 TV만

2. 하드웨어 가속

H.264 하드웨어 디코딩:
- CPU 사용률: 5-10%
- 배터리 소모: 낮음
- 발열: 적음

H.265 소프트웨어 디코딩:
- CPU 사용률: 80-100%
- 배터리 소모: 높음
- 발열: 많음

3. 인코딩 비용

1시간 영상 인코딩:

H.264 (preset=medium):
- 시간: 10분
- 비용: $0.10 (AWS)

H.265 (preset=medium):
- 시간: 100분
- 비용: $1.00 (AWS)

10배 차이!

4. 특허 문제

H.264:
- 2023년 특허 만료
- 무료 사용 가능
- 법적 리스크 없음

H.265:
- 특허 유효
- 로열티 필요
- 특허 풀 복잡

실제 사용 현황 (2026년)

YouTube:
- 기본: H.264
- 4K: VP9 또는 AV1
- 8K: AV1

Netflix:
- 1080p 이하: H.264
- 4K: H.265 (지원 기기만)
- 4K: H.264 (나머지 기기)

Twitch:
- 모든 스트림: H.264

Zoom:
- 모든 통화: H.264

트러블슈팅

1. “Unsupported codec” 에러

문제: 일부 기기에서 재생 안됨

원인: 높은 프로파일/레벨

해결:

# Baseline Profile로 재인코딩
ffmpeg -i input.mp4 \
       -c:v libx264 \
       -profile:v baseline \
       -level 3.0 \
       -pix_fmt yuv420p \
       output.mp4

2. 파일 크기가 너무 큼

문제: 인코딩 후 파일이 원본보다 큼

원인: CRF 값이 너무 낮음

해결:

# CRF 값 증가 (23 → 28)
ffmpeg -i input.mp4 \
       -c:v libx264 \
       -crf 28 \
       -preset medium \
       output.mp4

3. 인코딩 속도가 너무 느림

문제: 인코딩에 시간이 너무 오래 걸림

해결:

# 빠른 프리셋 사용
ffmpeg -i input.mp4 \
       -c:v libx264 \
       -preset veryfast \
       -crf 23 \
       output.mp4

# 또는 하드웨어 인코더 사용
ffmpeg -i input.mp4 \
       -c:v h264_nvenc \  # NVIDIA GPU
       -preset fast \
       -crf 23 \
       output.mp4

4. SPS/PPS 추출 실패

문제: MP4에서 SPS/PPS를 찾을 수 없음

해결:

# Annex B 포맷으로 변환
ffmpeg -i input.mp4 \
       -c copy \
       -bsf:v h264_mp4toannexb \
       output.h264

# 첫 100바이트 확인
xxd -l 100 output.h264

마무리

H.2642026년에도 여전히 표준입니다.

핵심 요약:

  1. NAL Unit: H.264 비트스트림의 기본 단위
  2. SPS: 전체 비디오 설정 (해상도, 프로파일, 레벨)
  3. PPS: 프레임별 설정 (엔트로피 코딩, 양자화)
  4. 프로파일: Baseline (모바일), Main (스트리밍), High (고품질)
  5. 레벨: 해상도와 프레임 레이트 제한

H.264를 선택하는 이유:

  • ✅ 모든 기기 지원
  • ✅ 하드웨어 가속
  • ✅ 빠른 인코딩
  • ✅ 특허 만료 (무료)
  • ✅ 검증된 안정성

H.265를 선택하는 경우:

  • 4K/8K 고해상도
  • 저장 공간 중요
  • 최신 기기만 지원
  • 인코딩 시간 충분

실전 추천:

# 범용 웹 비디오 (YouTube, 블로그)
ffmpeg -i input.mp4 \
       -c:v libx264 \
       -profile:v high \
       -level 4.1 \
       -crf 23 \
       -preset medium \
       -c:a aac -b:a 128k \
       output.mp4

# 모바일 호환 (최대 호환성)
ffmpeg -i input.mp4 \
       -c:v libx264 \
       -profile:v baseline \
       -level 3.0 \
       -crf 28 \
       -preset fast \
       -pix_fmt yuv420p \
       -c:a aac -b:a 96k \
       output.mp4

# 고품질 아카이브
ffmpeg -i input.mp4 \
       -c:v libx264 \
       -profile:v high \
       -level 5.1 \
       -crf 18 \
       -preset slow \
       -c:a aac -b:a 192k \
       output.mp4

다음 단계:

  • 영상 스트리밍 프로토콜
  • WebM 컨테이너 포맷
  • FFmpeg 완벽 가이드

H.264는 앞으로도 수년간 표준으로 남을 것입니다! 🎬