MP4 컨테이너 포맷 완전 가이드 | ISO BMFF·moov·mdat·fMP4·FFmpeg 실전
이 글의 핵심
MP4(ISO BMFF)는 글로벌 표준에 가장 가까운 범용 컨테이너—박스 구조·스트리밍 최적화·fMP4까지 한 흐름으로 정리합니다.
들어가며
MP4는 파일 확장자로 익숙하지만, 규격상 이름은 ISO Base Media File Format(ISO BMFF, ISO/IEC 14496-12) 위에 MPEG-4 시스템(14496-14 등) 관례를 얹은 형태로 이해하는 것이 정확합니다. H.264/H.265/AV1 비디오와 AAC 오디오를 같은 파일에 담는 가장 보편적인 상자(container)이며, 모바일·OTT·웹·편집 툴이 모두 기대하는 “기본 포맷”입니다.
이 글을 읽으면
- ISO BMFF 박스 트리(ftyp, moov, mdat)를 도식으로 설명할 수 있습니다
- 프로그레시브 재생(faststart)과 fragmented MP4(HLS/DASH)의 차이를 업무 기준으로 구분할 수 있습니다
- 리먹스·메타데이터·트랙 맵핑을 FFmpeg로 처리하는 패턴을 복사해 쓸 수 있습니다
- 호환성·오버헤드를 다른 컨테이너와 비교해 포맷을 선택할 근거를 갖습니다
목차
컨테이너 개요
역사 및 개발 배경
ISO BMFF는 QuickTime 파일 포맷의 정리·일반화를 거쳐 MPEG-4 Part 12로 표준화되었고, 이후 MP4 파일은 주로 14496-14(MPEG-4 파일 포맷)의 프로파일 관점에서 오디오·비디오 트랙 조합을 규정합니다.
주요 마일스톤:
- 2001: MPEG-4 Part 14 (MP4) 표준화
- 2004: ISO BMFF (Part 12) 분리
- 2013: CMAF (Common Media Application Format) 등장
- 2026: HLS/DASH fMP4 사실상 표준
기술적 특징
| 항목 | 설명 |
|---|---|
| 구조 | Box/Atom 기반 계층 구조 |
| 코덱 | H.264, HEVC, AV1, AAC, AC3 등 |
| 메타데이터 | moov 박스 내 트랙·타임라인 정보 |
| 스트리밍 | Progressive (faststart), Fragmented (fMP4) |
| 확장자 | .mp4 (비디오), .m4v (비디오), .m4a (오디오) |
내부 구조
Box/Atom 구조
MP4는 Box 단위로 구성됩니다. 각 Box는:
- 4 bytes: 크기
- 4 bytes: 타입 (fourcc)
- N bytes: 데이터
주요 Box:
MP4 파일
├─ ftyp (File Type)
│ ├─ major_brand: isom
│ └─ compatible_brands: isom, iso2, mp41
├─ moov (Movie)
│ ├─ mvhd (Movie Header)
│ ├─ trak (Track 1: Video)
│ │ ├─ tkhd (Track Header)
│ │ ├─ mdia (Media)
│ │ │ ├─ mdhd (Media Header)
│ │ │ ├─ hdlr (Handler: vide)
│ │ │ └─ minf (Media Info)
│ │ │ ├─ vmhd (Video Media Header)
│ │ │ ├─ dinf (Data Info)
│ │ │ └─ stbl (Sample Table)
│ │ │ ├─ stsd (Sample Description: avc1)
│ │ │ ├─ stts (Time-to-Sample)
│ │ │ ├─ stsc (Sample-to-Chunk)
│ │ │ ├─ stsz (Sample Size)
│ │ │ └─ stco (Chunk Offset)
│ ├─ trak (Track 2: Audio)
│ │ └─ ... (유사 구조, hdlr: soun, stsd: mp4a)
│ └─ udta (User Data: 메타데이터)
└─ mdat (Media Data: 실제 압축 샘플)
Progressive vs Fragmented
Progressive MP4
[ftyp][moov][mdat]
- moov: 전체 타임라인 한 번에
- mdat: 모든 미디어 데이터
- faststart: moov를 앞으로 이동
Fragmented MP4 (fMP4)
[ftyp][moov][moof][mdat][moof][mdat]...
- moov: 초기화 정보만
- moof: 각 세그먼트 메타데이터
- mdat: 세그먼트 미디어 데이터
장점:
- 라이브 스트리밍 가능
- 적응형 비트레이트 (ABR)
- 세그먼트 단위 캐싱
실전 사용
기본 명령
1) 구조 확인
# 스트림 정보
ffprobe -hide_banner -show_format -show_streams input.mp4
# Box 구조 (mp4dump - Bento4)
mp4dump input.mp4 | head -50
2) 무손실 리먹스
# MKV → MP4 (코덱 복사)
ffmpeg -i input.mkv -c copy -movflags +faststart output.mp4
# AVI → MP4
ffmpeg -i input.avi -c copy output.mp4
3) 인코딩 + faststart
# H.264 + AAC (웹 최적화)
ffmpeg -i input.mov \
-c:v libx264 \
-preset medium \
-crf 23 \
-pix_fmt yuv420p \
-c:a aac \
-b:a 192k \
-movflags +faststart \
output.mp4
고급 옵션
Fragmented MP4 생성
# fMP4 (HLS/DASH용)
ffmpeg -i input.mp4 \
-c copy \
-f mp4 \
-movflags frag_keyframe+empty_moov+default_base_moof \
fragmented.mp4
플래그 설명:
frag_keyframe: 키프레임마다 fragmentempty_moov: moov를 최소화default_base_moof: moof 기반 오프셋
메타데이터 추가
# 기본 태그
ffmpeg -i input.mp4 \
-c copy \
-metadata title="영화 제목" \
-metadata artist="감독" \
-metadata date="2026" \
-metadata comment="설명" \
tagged.mp4
다중 오디오 트랙
# 비디오 + 다중 오디오
ffmpeg -i video.mp4 \
-i audio_kor.wav \
-i audio_eng.wav \
-map 0:v:0 \
-map 1:a:0 \
-map 2:a:0 \
-c:v copy \
-c:a aac -b:a 192k \
-metadata:s:a:0 language=kor -metadata:s:a:0 title="한국어" \
-metadata:s:a:1 language=eng -metadata:s:a:1 title="English" \
-disposition:a:0 default \
multi_audio.mp4
HLS 세그먼트 생성
# HLS fMP4 세그먼트
ffmpeg -i input.mp4 \
-c:v libx264 -preset medium -crf 23 \
-c:a aac -b:a 128k \
-f hls \
-hls_time 6 \
-hls_playlist_type vod \
-hls_segment_type fmp4 \
-hls_fmp4_init_filename init.mp4 \
-hls_segment_filename segment_%03d.m4s \
playlist.m3u8
성능 비교
컨테이너 오버헤드
| 컨테이너 | 오버헤드 | 메타데이터 | 시크 성능 |
|---|---|---|---|
| MP4 | 매우 낮음 (< 1%) | 중간 | 우수 |
| MKV | 낮음 (< 1%) | 풍부 | 우수 |
| WebM | 매우 낮음 (< 1%) | 제한적 | 우수 |
결론: 컨테이너 오버헤드는 거의 무시 가능
스트리밍 비교
| 프로토콜 | Progressive MP4 | Fragmented MP4 |
|---|---|---|
| HTTP 단일 파일 | 우수 (faststart) | 가능 |
| HLS | 가능 (TS 대체) | 표준 (fMP4) |
| DASH | 가능 | 표준 (fMP4) |
| 라이브 | 부적합 | 적합 |
실무 활용 사례
사례 1: YouTube 업로드 최적화
요구사항:
- 고품질 유지
- 빠른 업로드
- 플랫폼 권장 설정
설정
# YouTube 권장 설정
ffmpeg -i input.mov \
-c:v libx264 \
-preset slow \
-crf 18 \
-pix_fmt yuv420p \
-profile:v high \
-level 4.2 \
-c:a aac \
-b:a 192k \
-ar 48000 \
-movflags +faststart \
youtube_upload.mp4
파라미터 설명:
-crf 18: 고품질 (YouTube 재인코딩 대비)-preset slow: 압축 효율 우선-profile:v high -level 4.2: 호환성
사례 2: 웹 비디오 플레이어
요구사항:
- 빠른 재생 시작
- 적응형 품질
- 브라우저 호환
다중 품질 생성
# 1080p
ffmpeg -i input.mp4 \
-vf "scale=1920:1080" \
-c:v libx264 -preset medium -crf 23 \
-c:a aac -b:a 192k \
-movflags +faststart \
1080p.mp4
# 720p
ffmpeg -i input.mp4 \
-vf "scale=1280:720" \
-c:v libx264 -preset medium -crf 24 \
-c:a aac -b:a 128k \
-movflags +faststart \
720p.mp4
# 480p
ffmpeg -i input.mp4 \
-vf "scale=854:480" \
-c:v libx264 -preset medium -crf 26 \
-c:a aac -b:a 96k \
-movflags +faststart \
480p.mp4
Python 자동화
import subprocess
from pathlib import Path
def create_multi_quality(input_file, output_dir):
"""
다중 품질 MP4 생성
"""
qualities = [
('1080p', '1920:1080', 23, '192k'),
('720p', '1280:720', 24, '128k'),
('480p', '854:480', 26, '96k')
]
Path(output_dir).mkdir(parents=True, exist_ok=True)
stem = Path(input_file).stem
for name, scale, crf, audio_br in qualities:
output_file = Path(output_dir) / f"{stem}_{name}.mp4"
cmd = [
'ffmpeg', '-y',
'-i', input_file,
'-vf', f'scale={scale}',
'-c:v', 'libx264',
'-preset', 'medium',
'-crf', str(crf),
'-c:a', 'aac',
'-b:a', audio_br,
'-movflags', '+faststart',
str(output_file)
]
print(f"Creating {name}...")
subprocess.run(cmd, check=True)
# 사용
create_multi_quality('master.mov', 'output')
사례 3: HLS 적응형 스트리밍
요구사항:
- 다중 비트레이트
- 세그먼트 기반
- CDN 캐싱
HLS 생성
# 마스터 플레이리스트 + 다중 variant
ffmpeg -i input.mp4 \
-filter_complex \
"[0:v]split=3[v1][v2][v3]; \
[v1]scale=1920:1080[v1out]; \
[v2]scale=1280:720[v2out]; \
[v3]scale=854:480[v3out]" \
-map "[v1out]" -c:v:0 libx264 -b:v:0 5000k \
-map "[v2out]" -c:v:1 libx264 -b:v:1 2800k \
-map "[v3out]" -c:v:2 libx264 -b:v:2 1400k \
-map 0:a -c:a aac -b:a 128k \
-f hls \
-hls_time 6 \
-hls_playlist_type vod \
-hls_segment_type fmp4 \
-hls_fmp4_init_filename init.mp4 \
-master_pl_name master.m3u8 \
-var_stream_map "v:0,a:0 v:1,a:0 v:2,a:0" \
stream_%v/playlist.m3u8
결과:
output/
├─ master.m3u8
├─ stream_0/
│ ├─ playlist.m3u8
│ ├─ init.mp4
│ ├─ segment_000.m4s
│ └─ segment_001.m4s
├─ stream_1/
│ └─ ...
└─ stream_2/
└─ ...
사례 4: 모바일 앱 - 오프라인 다운로드
요구사항:
- 파일 크기 최소화
- 빠른 재생
- 배터리 효율
설정
# 모바일 최적화
ffmpeg -i input.mp4 \
-vf "scale=1280:720" \
-c:v libx264 \
-preset fast \
-crf 26 \
-profile:v main \
-level 3.1 \
-c:a aac \
-b:a 96k \
-movflags +faststart \
mobile.mp4
최적화 포인트:
- Main Profile: 하드웨어 디코딩 지원
- Level 3.1: 저전력 기기 호환
- CRF 26: 파일 크기 절약
최적화 팁
1) 프로그레시브 재생 (faststart)
# 인코딩 시 적용
ffmpeg -i input.avi \
-c:v libx264 -c:a aac \
-movflags +faststart \
output.mp4
# 기존 파일에 적용
ffmpeg -i input.mp4 -c copy -movflags +faststart output.mp4
효과:
- moov를 파일 앞으로 이동
- 웹 재생 즉시 시작 가능
2) 파일 크기 최소화
# 불필요한 트랙 제거
ffmpeg -i input.mp4 \
-map 0:v:0 \
-map 0:a:0 \
-c copy \
slim.mp4
# 메타데이터 제거
ffmpeg -i input.mp4 \
-c copy \
-map_metadata -1 \
no_metadata.mp4
3) 호환성 개선
# 최대 호환 설정
ffmpeg -i input.mp4 \
-c:v libx264 \
-preset medium \
-crf 23 \
-profile:v baseline \
-level 3.0 \
-pix_fmt yuv420p \
-c:a aac \
-b:a 128k \
-ar 44100 \
-movflags +faststart \
compatible.mp4
트러블슈팅
문제 1: 웹에서 재생 안 됨
증상: HTML5 video 태그에서 재생 불가
<video src="video.mp4" controls></video>
<!-- 재생 안 됨 -->
원인 1: moov 위치
# faststart 적용
ffmpeg -i input.mp4 -c copy -movflags +faststart output.mp4
원인 2: 코덱 미지원
# 코덱 확인
ffprobe -v error -select_streams v:0 -show_entries stream=codec_name input.mp4
# HEVC → H.264 변환
ffmpeg -i input.mp4 \
-c:v libx264 -preset medium -crf 23 \
-c:a copy \
-movflags +faststart \
output.mp4
문제 2: 재생 시작 느림
증상: 다운로드 완료 후에야 재생 시작
원인: moov가 파일 끝에 위치
해결:
# faststart 적용
ffmpeg -i slow.mp4 -c copy -movflags +faststart fast.mp4
확인:
# moov 위치 확인 (mp4dump)
mp4dump slow.mp4 | grep -A 5 "moov"
문제 3: 자막 동기화 문제
증상: 자막이 영상과 어긋남
원인: 타임베이스 불일치
해결:
# 자막 재동기화
ffmpeg -i video.mp4 -i subtitle.srt \
-map 0:v -map 0:a -map 1:s \
-c:v copy -c:a copy \
-c:s mov_text \
-metadata:s:s:0 language=kor \
synced.mp4
문제 4: 모바일 재생 안 됨
증상: 특정 모바일 기기에서 재생 불가
원인: 프로파일/레벨 미지원
해결:
# Baseline Profile (최대 호환)
ffmpeg -i input.mp4 \
-c:v libx264 \
-preset medium \
-crf 23 \
-profile:v baseline \
-level 3.0 \
-pix_fmt yuv420p \
-c:a aac -b:a 128k \
-movflags +faststart \
mobile_compatible.mp4
마무리
MP4는 ISO BMFF 위에 세워진 사실상의 표준 배포 컨테이너이며, 실무 핵심은 moov/mdat 관계와 fMP4로의 전환을 이해하는 것입니다.
핵심 요약
-
구조
- Box/Atom 기반 계층 구조
- ftyp, moov, mdat 핵심 박스
- Progressive vs Fragmented
-
스트리밍
- faststart: 프로그레시브 재생
- fMP4: HLS/DASH 세그먼트
-
호환성
- 거의 모든 기기·플랫폼 지원
- H.264 + AAC 조합 최적
선택 가이드
| 상황 | 설정 |
|---|---|
| 웹 단일 파일 | Progressive MP4 + faststart |
| 적응형 스트리밍 | Fragmented MP4 (HLS/DASH) |
| 모바일 다운로드 | Progressive MP4 + Baseline Profile |
| 최대 호환 | H.264 + AAC + yuv420p |
FFmpeg 명령 치트시트
# 기본 인코딩
ffmpeg -i input.avi -c:v libx264 -c:a aac -movflags +faststart output.mp4
# 리먹스 (코덱 복사)
ffmpeg -i input.mkv -c copy -movflags +faststart output.mp4
# Fragmented MP4
ffmpeg -i input.mp4 -c copy -f mp4 -movflags frag_keyframe+empty_moov fragmented.mp4
# HLS 세그먼트
ffmpeg -i input.mp4 -c:v libx264 -c:a aac \
-f hls -hls_time 6 -hls_segment_type fmp4 playlist.m3u8
# 메타데이터 추가
ffmpeg -i input.mp4 -c copy -metadata title="제목" output.mp4
# 다중 오디오
ffmpeg -i video.mp4 -i audio.wav \
-map 0:v -map 0:a -map 1:a \
-c:v copy -c:a aac \
multi.mp4
다음 단계
- MKV 비교: MKV 실전 가이드
- WebM 비교: WebM 웹 표준
- H.264 코덱: H.264 완벽 가이드
참고 자료
- ISO BMFF: ISO/IEC 14496-12
- MP4: ISO/IEC 14496-14
- CMAF: ISO/IEC 23000-19
- FFmpeg: https://ffmpeg.org/ffmpeg-formats.html#mov_002c-mp4_002c-ismv
한 줄 정리: 크로스 플랫폼 VOD·모바일·웹 배포는 MP4 + faststart가 기본이고, 적응형 스트리밍은 fMP4로 세그먼트한다.