Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

4장. 데이터의 실체 — Segment 내부 구조

4.0 이 장을 시작하며

3장까지 우리는 HLS를 “playlist + segment“라는 추상 구조로 다뤘다.

이제 한 단계 내려간다.

segment 파일 안에는 실제로 무엇이 들어있는가?

이 질문에 답하지 않으면 다음 두 가지를 이해할 수 없다.

  • 왜 TS와 fMP4가 함께 존재하는가
  • 왜 LL-HLS는 fMP4여야만 가능한가

이 장은 책에서 가장 “실물“에 가까운 장이다.


4.1 컨테이너와 코덱의 구분

먼저 두 용어를 분리해야 한다.

자주 헷갈리지만, 이 둘은 완전히 다른 계층이다.


코덱 (Codec)

영상/음성을 압축하고 푸는 방식.

  • H.264 / H.265 / AV1 — 비디오 코덱
  • AAC / AC-3 / Opus — 오디오 코덱

코덱은 픽셀/소리 데이터를 비트의 흐름으로 만든다.


컨테이너 (Container)

코덱이 만든 데이터를 담는 봉투.

  • MPEG-TS (.ts)
  • MP4 / fMP4 (.mp4, .m4s)
  • MKV, WebM, MOV

컨테이너는 다음 정보를 담는다.

  • 어떤 코덱을 썼는가
  • 각 데이터의 타임스탬프
  • 트랙 정보 (오디오/비디오 분리)

비유

코덱은 음식이고 컨테이너는 도시락통이다.

같은 음식(H.264 비디오)을 다른 도시락통(TS, fMP4)에 담을 수 있다.

HLS에서 포맷 논의는 컨테이너 논의다. 코덱은 보통 H.264 + AAC로 고정되어 있다.


4.2 MPEG-TS 깊이 들여다보기

HLS가 처음 등장할 때부터 사용된 컨테이너가 MPEG-TS (Transport Stream)이다.

원래 이건 디지털 방송(DVB, ATSC)을 위해 만들어진 포맷이다.


4.2.1 188바이트 패킷의 구조

TS의 가장 중요한 특징:

모든 데이터가 188바이트 패킷 단위로 흘러간다

┌─── 188 bytes ────────────────────┐
│ Header (4B) │ Payload (184B)     │
└─────────────────────────────────┘

Header (4 bytes)

0x47          - sync byte (모든 패킷 시작)
TEI/PUSI/TP   - 플래그 비트 (1.5바이트)
PID           - 패킷 식별자 (13비트)
TSC/AFC/CC    - 스크램블/적응/연속성 카운터

이 패킷이 끝없이 이어진 것이 TS 스트림이다.


4.2.2 PID, PAT, PMT

여러 트랙(비디오/오디오)이 한 흐름으로 섞여 있는데 어떻게 구분할까?

각 패킷의 PID (Packet Identifier)로 구분한다.

PID=0x0100 → 비디오 트랙
PID=0x0101 → 오디오 트랙
PID=0x0102 → 자막 트랙

그런데 플레이어는 “어떤 PID가 어떤 트랙“인지 어떻게 알까?

특수한 두 테이블을 통해서다.


PAT (Program Association Table)

PID=0x0000 (고정)
→ "프로그램 목록과 그 PMT의 PID를 알려준다"

PAT는 일종의 메뉴판이다.

프로그램 1 → PMT의 PID는 0x1000

PMT (Program Map Table)

PID=0x1000 (PAT가 지정)
→ "이 프로그램의 비디오/오디오 PID를 알려준다"

PMT는 상세 안내서다.

비디오: PID=0x0100, 코덱 H.264
오디오: PID=0x0101, 코덱 AAC

패킷 흐름 예시

[PAT] [PMT] [Video] [Video] [Audio] [Video] [Audio] ...

플레이어는 다음 순서로 동작한다.

1. 188바이트씩 읽는다
2. 첫 번째 PAT를 만나 → 프로그램 목록 확인
3. PMT를 만나 → 비디오/오디오 PID 학습
4. 각 PID에 해당하는 패킷을 모아 디코더로 전달

4.2.3 PES (Packetized Elementary Stream)

비디오/오디오 데이터는 바로 패킷에 들어가지 않는다.

한 번 더 포장된다.

Elementary Stream (코덱 출력 raw 비트)
  ↓
PES Packet (타임스탬프 + 헤더 + 데이터)
  ↓
TS Packet (188바이트로 잘려서)

PES 헤더에는 다음이 들어있다.

  • PTS (Presentation Timestamp) — 언제 보여줄지
  • DTS (Decoding Timestamp) — 언제 디코딩할지

이게 있어야 오디오와 비디오가 싱크가 맞춰진다.


4.2.4 왜 TS는 중간부터 재생이 어려운가

이제 구조적 이유가 보인다.

  • 한 프레임의 데이터가 여러 TS 패킷에 걸쳐 분산되어 있다
  • PAT/PMT는 주기적으로 반복되지만 랜덤 위치에서 만나려면 운이 좋아야 한다
  • PES 헤더와 본문이 떨어져 있을 수 있다

결과:

TS는 “흐름“으로 설계됐기 때문에 임의의 지점에서 잘라내기가 어렵다

이게 5장에서 다룰 latency 문제와 6장에서 fMP4가 필요해진 이유로 이어진다.


4.3 fMP4 깊이 들여다보기

fMP4 (fragmented MP4)는 MP4 컨테이너의 한 형태다.

먼저 MP4의 구조를 알아야 한다.


4.3.1 MP4의 “Box” 개념

MP4는 모든 데이터를 Box (또는 Atom) 단위로 담는다.

각 box의 구조:

┌─── Box ────────────────┐
│ size (4B)              │
│ type (4B, 예: "ftyp") │
│ data (...)             │
└────────────────────────┘

Box는 트리 구조다. 부모 box 안에 자식 box가 들어간다.


일반 MP4 구조

ftyp        ← 파일 타입
moov        ← 메타데이터 (재생 정보)
├── mvhd
├── trak (비디오)
│   └── mdia
│       └── minf
│           └── stbl
│               ├── stsd  (코덱 정보)
│               ├── stts  (타임스탬프)
│               └── stsz  (크기 테이블)
└── trak (오디오)
mdat        ← 실제 미디어 데이터

문제는 이 구조에 있다.

  • moov에는 모든 프레임의 위치 인덱스가 들어있다
  • 즉 영상이 끝나야 moov가 완성된다

라이브에서 사용할 수 없다는 뜻이다.


4.3.2 ftyp / moov / mvex

fMP4는 이 문제를 해결한다.

ftyp        ← 파일 타입
moov        ← 트랙 정의만 (인덱스 없음!)
├── mvhd
├── trak
└── mvex    ← "이후 fragment가 이어진다"는 선언

mvex (Movie Extends) box가 핵심이다.

이 box가 있으면 “moov는 미완성이고, 뒤에 fragment가 추가된다“는 뜻이다.

ftyp + moov + mvex 묶음을 Initialization Segment라 부른다. (HLS의 EXT-X-MAP이 가리키는 것)


4.3.3 moof / mdat

본체 segment는 moof + mdat 쌍의 반복이다.

moof (fragment 1)
mdat (fragment 1 data)

moof (fragment 2)
mdat (fragment 2 data)

moof (fragment 3)
mdat (fragment 3 data)

moof (Movie Fragment) 내부:

moof
├── mfhd      ← fragment 번호
└── traf      ← 트랙별 fragment 정보
    ├── tfhd  ← 트랙 헤더
    ├── tfdt  ← 타임스탬프
    └── trun  ← 샘플(프레임) 목록과 위치

mdat: 실제 인코딩된 비디오/오디오 데이터.


4.3.4 sidx와 랜덤 액세스

sidx (Segment Index)

VOD에서 자주 등장하는 box.

각 fragment의 위치와 시간 범위를 미리 인덱스로 제공한다.

플레이어는 sidx를 보고 “5분 30초 지점은 byte offset 12000000“이라는 식으로 즉시 점프할 수 있다.

라이브에서는 sidx가 없다. (어차피 끝이 정해지지 않았으므로)


4.3.5 왜 fMP4는 독립 재생이 가능한가

핵심을 보자.

  • moof는 그 자체로 fragment의 모든 메타데이터를 가진다
  • mdat은 keyframe부터 시작하는 독립 디코딩 가능한 영상을 담는다
  • 앞 fragment를 몰라도 init.mp4만 있으면 재생 가능하다

즉:

fMP4의 fragment는 그 자체로 “작은 완성품“이다

이게 LL-HLS가 가능해진 이유다.

TS:    [────────────────] 흐름 (자를 곳을 정하기 어려움)

fMP4:  [✓][✓][✓][✓][✓]    각각이 독립 조각

4.4 GOP과 Keyframe Alignment

4.4.1 I / P / B 프레임의 차이

영상 압축은 모든 프레임을 통째로 저장하지 않는다.

세 종류로 나눈다.

종류의미크기
I-Frame자기 자신만으로 완성된 프레임크다
P-Frame이전 프레임과의 차이만 저장중간
B-Frame양쪽 프레임을 참조 (앞/뒤)작다

GOP (Group of Pictures)

I-Frame 하나로 시작해서 다음 I-Frame이 나오기 전까지의 묶음.

[I, P, P, B, P, B, P, P, I, P, P, ...]
 └──────── GOP 1 ────┘└─ GOP 2 ─
  • I-Frame: keyframe이라고도 부른다
  • GOP 길이는 보통 1~5초

4.4.2 왜 segment 경계는 keyframe이어야 하는가

ABR을 다시 떠올려보자.

seg1: 1080p (GOP A)
seg2: 720p  (GOP B)  ← 화질 전환

만약 seg2가 P-Frame으로 시작한다면?

P-Frame은 이전 프레임이 있어야 디코딩 가능하다.

그런데 seg1은 1080p, seg2는 720p. 참조할 이전 프레임이 없다.

→ 디코딩 실패

그래서 규칙이 정해진다.

모든 segment는 I-Frame(keyframe)으로 시작해야 한다


4.4.3 인코더의 segment 경계 처리

이를 보장하려면 인코더는 GOP 경계와 segment 경계를 일치시켜야 한다.

GOP:     [I────][I────][I────][I────]
Segment: [────][────][────][────]
         ↑일치  ↑일치  ↑일치  ↑일치

이를 closed GOP + segment alignment라고 부른다.

추가로, 여러 화질 사이에서도 이 경계가 동일해야 한다.

1080p: [I────][I────][I────]
720p:  [I────][I────][I────]
480p:  [I────][I────][I────]
       ↑모두 같은 시점에 keyframe

이 정렬을 keyframe alignment라고 한다.

ffmpeg에서는 보통 이렇게 강제한다.

-g 60 -keyint_min 60 -force_key_frames "expr:gte(t,n_forced*2)"

(2초마다 강제 keyframe)


4.5 코덱 호환성

4.5.1 비디오 코덱

코덱별명특징
H.264AVC가장 호환성 높음, 디폴트
H.265HEVC압축 효율 ↑, 라이선스 복잡
AV1로열티 프리, 인코딩 느림
VP9YouTube가 주도, 브라우저 위주

HLS는 전통적으로 H.264. 4K HDR에는 HEVC를 쓰기 시작했다.


4.5.2 오디오 코덱

코덱특징
AACHLS의 표준
AC-3 / E-AC-35.1 채널, 영화/TV
Opus저지연, 음성 중심

4.5.3 CODECS 문자열 읽는 법

EXT-X-STREAM-INFCODECS 속성은 정해진 포맷이다.

예시:

CODECS="avc1.640028,mp4a.40.2"

비디오: avc1.640028

avc1     → H.264 (AVC)
64       → Profile (High)
0028     → Level (4.0)
Profile 코드이름
42Baseline
4DMain
64High
Level 코드 (10진 표기)의미
1F (31)Level 3.1 (720p30)
28 (40)Level 4.0 (1080p30)
33 (51)Level 5.1 (4K)

오디오: mp4a.40.2

mp4a     → MPEG-4 Audio
40       → AAC family
2        → AAC-LC
마지막 숫자의미
2AAC-LC
5HE-AAC
29HE-AAC v2

플레이어는 이 문자열을 보고 자신이 지원하는 코덱인지 판단한다.

지원하지 않으면 그 variant를 건너뛴다.


4.6 정리: 왜 TS와 fMP4가 공존하는가

이제 두 포맷의 위치가 명확해진다.

구분MPEG-TSfMP4
설계 목적방송 송출파일 + 스트리밍
데이터 형태188B 패킷 흐름Box 트리
독립 재생어려움각 fragment 가능
init 분리불필요 (PAT/PMT 반복)필요 (EXT-X-MAP)
라이브 친화성매우 높음매우 높음 (LL-HLS)
압축 효율보통좋음 (오버헤드 적음)
HEVC 지원제약 있음우수
HLS 버전v1부터v7 이후
호환성거의 모든 곳최신 플레이어

둘 다 살아남은 이유

  • TS는 호환성과 안정성
  • fMP4는 효율성과 LL-HLS

특히 fMP4는 DASH와 동일한 컨테이너라서 한 파일로 양쪽에서 재생할 수 있다.

이게 7장에서 다룰 CMAF의 핵심이다.


4장 한 줄 정리

같은 영상도 TS에서는 흐름으로 흩어지고, fMP4에서는 독립된 조각들의 묶음이 된다. 이 차이가 Low Latency를 가르는 출발점이다.