📁 File3. 비디오03 · Frame Rate · Timing · Timecode

03 · Frame Rate · Timing · Timecode

이 문서가 답하는 질문: 23.976fps는 왜 존재하며, drop-frame timecode란 무엇인가? 선행: 02-progressive-vs-interlaced.md


한 줄 답

프레임레이트는 “초당 프레임 수”이지만, 실제 표준은 모두 분수다(24/1.001, 30/1.001, …). 1953년 NTSC 컬러TV 호환성 결정의 결과로 0.1% 만큼 느려진 시간 — 그 0.1%를 보정하는 게 drop-frame timecode다.


Why — 왜 23.976이 존재하는가

1953년, NTSC 컬러TV 표준을 만들 때 흑백 TV와의 호환 이 강제됐다. 컬러 부반송파를 추가하면서 30 fps를 그대로 유지하면 음성 반송파와 비트가 섞이는 간섭이 생긴다는 것이 RCA의 측정 결과.

해결책: frame rate를 0.1% 줄여 29.97 fps로. 정확히는:

30 / 1.001 ≈ 29.9700299... fps

이 결정이 60년이 지난 지금 모든 미디어 시스템에 그림자를 드리운다.

”이름”실제 값출처
24p24.000영화 (35mm 필름 표준)
23.976p24/1.001 ≈ 23.976영화→NTSC 변환용 (텔레시네 베이스)
25p25.000PAL/SECAM (유럽 50Hz)
29.97p / 29.97i30/1.001 ≈ 29.970NTSC 비디오
30p30.000디지털 (게임·웹)
50p / 50i50.000PAL HD
59.94p / 59.94i60/1.001 ≈ 59.940NTSC HD
60p60.000디지털 (게임·웹)
120p120.0008K NHK·고프레임 캡처

→ NTSC 계열은 모두 1/1.001 = 0.999000999... 만큼 느리다. 이걸 무시하면 24시간에 약 86초 어긋난다.


How — 어떻게 동작하는가

Drop-frame Timecode (DF) — 0.1%의 청구서

Timecode는 영상의 시간 좌표(HH:MM:SS:FF, FF는 프레임 029). 29.97 fps인데 timecode는 029 라벨을 쓴다 — 즉 30 fps의 라벨을 29.97 fps에 붙이는 모순.

해결: 매 분마다 2개 프레임 라벨을 건너뛴다 (단, 매 10분째는 건너뛰지 않음).

00:00:59:29 → 00:01:00:02   ← 00:01:00:00, 00:01:00:01 라벨 스킵
00:09:59:29 → 00:10:00:00   ← 매 10분은 스킵 안 함

이 패턴으로 60분 동안 정확히 (60-6) × 2 = 108 프레임 만큼 라벨을 건너뛰면서 wall-clock 시간과 일치하게 만든다.

프레임은 그대로 있다 — 라벨만 바뀐다는 점이 핵심. 그래서 “drop frame”은 사실 drop label.

표기의미
01:00:00:00 (NDF, non-drop-frame)라벨 건너뛰기 없음 → 실시간보다 0.1% 길어짐
01:00:00;00 (DF, semicolon)라벨 건너뛰기 있음 → 실시간 일치

→ 24fps 영화나 25fps PAL은 정수 fps라 DF가 필요 없다. NTSC 계열에만 존재하는 트릭.

VFR (Variable Frame Rate) vs CFR (Constant Frame Rate)

모드설명사용처
CFR모든 프레임 간격이 같음방송·전통적 비디오 표준
VFR프레임 간격이 가변 (PTS만 정확)화면 녹화 (OBS·QuickTime), 모바일 카메라

화면 녹화기는 변경된 프레임만 기록해 디스크/CPU를 아낀다 — 이게 VFR. 문제는 NLE(Premiere·Resolve)·일부 인코더가 CFR을 가정해서, VFR 자산을 그대로 임포트하면 오디오 sync drift가 생긴다.

# VFR 진단
ffprobe -select_streams v:0 -show_entries packet=pts_time \
  -of csv input.mp4 | head -20
# → pts_time이 균일 간격이면 CFR, 불규칙이면 VFR
 
# VFR을 CFR로 정규화 (편집 전 필수)
ffmpeg -i screen.mp4 -vsync cfr -r 60 -c:v libx264 cfr.mp4
 
# fps 필터로 확정
ffmpeg -i in.mp4 -vf "fps=30" -c:v libx264 out.mp4

PTS / DTS — 컨테이너의 시간 좌표

약어풀이역할
PTS (Presentation TS)프레임을 언제 표시 할지디스플레이 타임스탬프
DTS (Decode TS)프레임을 언제 디코딩 할지B-frame 때문에 PTS와 다름

B-frame이 있으면 디코딩 순서 ≠ 표시 순서 → DTS와 PTS가 분리된다 (08-codec-h264.md GOP).

표시 순서: I  B  B  P  B  B  P
디코딩 순서: I  P  B  B  P  B  B

What — 자주 쓰는 fps 가이드와 명령어

콘텐츠별 권장 frame rate

콘텐츠권장 fps이유
영화 (시네마)24p100년 표준. cinematic motion blur 와 일치
드라마/방송23.976p / 29.97pNTSC 호환
스포츠/뉴스50p / 59.94p빠른 모션·실시간
게임 스트리밍60p게임 자체가 60+
인터뷰·토크30p자연스럽고 가벼움
슬로모션 캡처120p / 240p / 480p고프레임으로 찍어 30/60p로 재생
TikTok/Reels30p / 60p모바일 디스플레이 표준
VR / AR90p+멀미 방지

ffmpeg fps 변환 패턴

# 1. 단순 fps 변경 (프레임 drop/duplicate)
ffmpeg -i in.mp4 -r 30 out.mp4
 
# 2. fps 필터 (더 정확)
ffmpeg -i in.mp4 -vf "fps=30" out.mp4
 
# 3. 60p → 30p 안전 변환
ffmpeg -i 60p.mp4 -vf "fps=30" -c:v libx264 30p.mp4
 
# 4. 24p → 60p 모션 보간 (minterpolate)
ffmpeg -i 24p.mp4 -vf "minterpolate=fps=60:mi_mode=mci" smooth60p.mp4
 
# 5. 슬로모션 (240p 캡처 → 30p로 재생 = 8배 슬로)
ffmpeg -i 240p_capture.mp4 -filter:v "setpts=8*PTS" -r 30 slow.mp4
 
# 6. 23.976 ↔ 24 변환
ffmpeg -i 23976.mp4 -vf "fps=24" -af "atempo=1.001" out24.mp4

Timecode 다루기

# 입력 timecode 확인
ffprobe -show_entries stream_tags=timecode in.mov
 
# timecode 삽입
ffmpeg -i in.mp4 -timecode 01:00:00:00 -c copy out.mp4
 
# drop-frame 명시 (29.97)
ffmpeg -i in.mov -timecode "01:00:00;00" -r 30000/1001 -c copy out.mov

What-if — 잘못 다루면 어떻게 깨지는가

❌ 함정 1 — 23.976을 24로 라운딩

비디오 fps를 24.000으로 잡고 오디오는 그대로 두면, 80분 짜리 영화에서 ~5초 누적 sync drift. → 시청자가 입모양이 안 맞는다고 보고하는 가장 흔한 케이스.

# 잘못
ffmpeg -i in.mov -r 24 -c:a copy out.mp4
 
# 올바름 (1.001 비율 보존)
ffmpeg -i in.mov -r 24000/1001 -c:a copy out.mp4

❌ 함정 2 — VFR을 CFR로 인식해 인코딩

OBS 녹화·iPhone 캡처는 VFR. 그대로 NLE에 넣으면 timeline이 prefer “30 fps CFR”로 해석 → 장면 전환 후 점진적 oudio drift.

# 진단
ffprobe -select_streams v:0 -show_entries stream=avg_frame_rate,r_frame_rate in.mp4
# avg_frame_rate=30/1, r_frame_rate=600/1 → VFR 의심
# (r_frame_rate은 timebase 분모, 값이 매우 크면 VFR)
 
# CFR 정규화 후 편집
ffmpeg -i screen.mp4 -vsync cfr -r 30 -c:v libx264 -crf 18 cfr.mp4

❌ 함정 3 — drop-frame timecode 오해

01:00:00;00 (DF) 와 01:00:00:00 (NDF)를 같은 시각으로 착각해서 편집실에서 1시간 마크에 광고를 넣었더니 방송 송출 시 광고가 3.6초 뒤에 시작.

→ NDF에서 1시간 라벨은 wall-clock 1시간 + 3.6초.

❌ 함정 4 — 60p → 30p drop만으로 처리

# bad: 단순 frame drop → 모션이 끊김
ffmpeg -i 60p.mp4 -r 30 -c:v libx264 out.mp4
 
# good: fps 필터 (motion-aware blending 옵션 가능)
ffmpeg -i 60p.mp4 -vf "fps=30" -c:v libx264 out.mp4
 
# better: 모션 블러 합성으로 영화 같은 셔터
ffmpeg -i 60p.mp4 -vf "tblend=all_mode=average,fps=30" -c:v libx264 out.mp4

❌ 함정 5 — 모션 보간(minterpolate)을 영화에 적용

24p 영화를 60p로 minterpolate하면 soap opera effect — 영화가 드라마처럼 너무 매끄럽게 보이는 현상. 극장의 24p는 cinematic. 일부러 그 느낌을 위한 것이고 보간하면 영화감이 사라진다.


Insight — 흥미로운 이야기

“24fps는 사람이 보기 편한 숫자가 아니다”

24 fps는 1920년대 사운드 영화 등장 시 광학 사운드 트랙을 읽기 위한 최저 필름 속도. 이전 무성영화는 16~22 fps가 흔했고, 24는 사운드 동기화의 최소 속도. 1927년 The Jazz Singer 이후 표준이 됐다 — 기술적 한계가 미적 표준이 된 사례.

“NTSC = Never Twice Same Color”

NTSC의 0.1% drift는 50년 동안 방송업계의 농담이었다. 1953년 라디오·흑백TV·신생 컬러TV의 호환성을 위해 도입됐고, 그 결과로 23.976/29.97/59.94가 만들어졌다. 1990년대 ATSC 디지털 방송이 와도 호환을 위해 그대로 끌고 왔고, 2025년 OTT까지 영향이 남는다.

“PAL/SECAM은 깔끔한 25를 가졌지만…”

유럽은 50Hz 전력망 → 25fps. 영화 24를 PAL로 변환할 때는 4% 빠르게 재생 (“PAL speedup”). 영화는 24 → 25, 약 4분 단축. 음악도 같은 4% 올라가서 A=440Hz가 A♯ 가까이 올라간다. 비틀스 LP 영국판과 미국판이 음높이가 다른 게 이 때문 — 프레임레이트가 음악의 키를 바꾼 사건.


요약 + Mermaid

24·25·30이 아니라 24/1.001·25·30/1.001 — 1953년 NTSC 컬러TV의 0.1%가 모든 디지털 미디어에 박혀있다. Drop-frame timecode는 라벨을 건너뛰어 실시간과 맞추는 트릭이고, VFR/CFR 혼동은 sync drift의 1순위. 영화는 24p, 방송은 23.976/29.97, 게임/스포츠는 60p가 정석이며, fps 변환은 단순 drop이 아니라 fps 필터로 한다.