본문으로 건너뛰기
Previous
Next
[2026] HLS(HTTP Live Streaming) 완전 참조 — M3U8·ABR·암호화·LL-HLS

[2026] HLS(HTTP Live Streaming) 완전 참조 — M3U8·ABR·암호화·LL-HLS

[2026] HLS(HTTP Live Streaming) 완전 참조 — M3U8·ABR·암호화·LL-HLS

이 글의 핵심

HLS는 HTTP 기반 적응형 스트리밍 사실상의 표준입니다. 이 글은 RFC 8216·확장 태그, TS와 fMP4(CMAF) 세그먼트, FFmpeg로의 인코딩·암호화·ABR, FairPlay, CDN, LL-HLS(저지연), 그리고 hls.js·Video.js·Safari에서의 구현·오류 처리까지 한 권짜리 참조로 정리합니다.

HTTP Live Streaming(HLS)은 미디어 세그먼트와 재생 목록(m3u8)을 일반 HTTP로 전달하는 적응형 스트리밍 형식입니다. IETF RFC 8216로 문서화되어 있으며, 마스터 플레이리스트가 변별(variant) 스트림을 가리키고, 미디어 플레이리스트가 실제 TS 또는 fMP4 조각의 URL·메타데이터를 나열하는 구조로 이해하면 됩니다. 이 글은 스펙 해석, 인코딩(FFmpeg), 암호화·DRM, 저지연(LL-HLS), 배포, 클라이언트(브라우저) 구현을 참조서 형태로 묶습니다.

전제: 스펙은 시간에 따라 확장 태그와 업체 구현(특히 Apple·방송)이 추가됩니다. 운영 시에는 대상 클라이언트가 해석하는 태그 집합을 기준으로 검증하십시오.


1. 프로토콜 스펙 (RFC 8216)

1.1 M3U8 포맷

HLS는 텍스트 기반 재생 목록(playlist) 입니다. UTF-8로 인코딩하는 것이 권고되며, 확장자로는 m3u8이 관례입니다. RFC 8216 §3에 따르면, 유효한 미디어 플레이리스트는 #EXTM3U로 시작해야 하고, (미디어 플레이리스트의 경우) #EXT-X-VERSION이 필요합니다.

  • 주석/태그: #으로 시작. #EXT로 시작하는 것은 구조화된 태그입니다.
  • URI 줄: 태그에 대한 보조 정보가 아니라, 세그먼트·리소스 URL이 한 줄에 올 수 있습니다(상대·절대 URI).
  • 줄 끝: CRLF 권고; 일부 구현은 LF만 허용합니다.

구문 해석 시 주의: 동일한 태그가 여러 번 등장하는 규칙(예: 키 회전)과, EXTINF 지속시간부동소수로 표시되는 점(버전 3 이상)을 함께 봐야 합니다.

1.2 Master Playlist vs Media Playlist

구분Master PlaylistMedia Playlist
역할변별 스트림 목록(해상도·비트레이트 등)미디어 세그먼트 나열·메타
흔한 태그EXT-X-STREAM-INF, (선택) EXT-X-I-FRAME-STREAM-INFEXT-X-TARGETDURATION, EXT-X-MEDIA-SEQUENCE, EXTINF, EXT-X-KEY, EXT-X-MAP
URIEXT-X-STREAM-INF 다음 줄에 variant URL각 세그먼트(또는 byte range) URI
  • 클라이언트(ABR): 마스터를 받아 대역폭·코덱 등에 따라 variant를 고르고, 이후 해당 미디어 플레이리스트만 갱신하며 다운로드합니다.
  • VOD vs LIVE: EXT-X-ENDLIST가 있으면 보통 VOD(고정), 없으면 라이브(슬라이딩 윈도우)로 갱신합니다.

1.3 EXT-X 태그 (핵심·참조)

아래는 RFC 8216에 정의된 태그를 빠짐없이 짚되, 모든 전송·서비스에서 동일하게 쓰이지는 않으므로 지원 여부는 플레이어 매트릭스로 확인해야 합니다.

태그용도
EXTM3UM3U 확장 형식임을 표시(첫 줄)
EXT-X-VERSION호환 버전(태그/규칙 수준)
EXT-X-INDEPENDENT-SEGMENTS(선언 시) 세그먼트가 독립 디코딩 가능
EXT-X-TARGETDURATION세그먼트 최대 길이(초, 올림 정수)
EXT-X-MEDIA-SEQUENCE첫 URL 세그먼트의 시퀀스 번호
EXT-X-DISCONTINUITY-SEQUENCE불연속 카운트(타임스탬프·인코딩 점프 대응)
EXT-X-START재생 시작 오프셋
EXT-X-ENDLIST더 이상 세그먼트 없음(VOD 끝)
EXT-X-KEY세그먼트 암호화 방법·키 URI
EXT-X-MAPfMP4 초기화 세그먼트(init)
EXT-X-PROGRAM-DATE-TIME절대 시각 (동기·광고 등)
EXT-X-DATE-RANGE콘텐츠·메타데이터 구간(이벤트)
EXTINF다음 URI의 지속시간(초)
EXT-X-BYTERANGE다음 URI의 서브범위
EXT-X-DISCONTINUITY인코딩/타임라인 불연속 표시
EXT-X-STREAM-INF (마스터)variant 속성 + 다음 줄 variant URI
EXT-X-I-FRAME-STREAM-INFI-프레임 전용 RENDITION
EXT-X-SESSION-KEY마스터 수준 “세션” 키(복호)
EXT-X-SESSION-DATA세션 메타데이터(ID·URI 등)
EXT-X-INDEPENDENT-SEGMENTS(마스터) 전체 independent 선언에 사용 가능

참고: RFC 8216 §4문법§6플레이리스트 예가 있습니다. EXT-X-STREAM-INFBANDWIDTH, RESOLUTION, CODECS 등은 ABR·호환에 직접적입니다.

1.4 Transport Stream(TS) vs fMP4(CMAF) 세그먼트

  • MPEG-2 TS(.ts): 전통적인 HLS 조각. PAT/PMT + PES 단위 흐름에 익숙한 방송·레거시 인코더가 많습니다.
  • fMP4(분할 MP4) / CMAF: 초기화 세그먼트(EXT-X-MAP) + 미디어 세그먼트가 쌍을 이룹니다. RFC 8216 §3.3 EXT-X-MAP 참고. 동일 CMAF 추적을 DASH·HLS 양쪽에 맞출 때 유리합니다.

선택 기준(실무): CDN·캐시 키·클라이언트·인코더가 fMP4를 지원하면 CMAF/fMP4가 중복 인코딩·저장을 줄이는 데 유리한 경우가 많고, TS는 툴체인·호환 쪽에서 여전히 흔합니다.

1.5 바이트 레인지(Byte Range)

EXT-X-BYTERANGE다음 URI가 가리키는 리소스의 부분 바이트 범위를 의미합니다. RFC 8216 §4.3.2 형식은 @ 유무에 따라 “길이만” 또는 “오프셋+길이”로 해석됩니다. 같은 URL에 연속 byte range로 여러 세그먼트를 매핑하면 HTTP 캐시 효율을 노릴 수 있으나, 오리진·CDN이 Range 요청·캐시를 올바르게 지원해야 합니다.

#EXTM3U
#EXT-X-VERSION:4
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:6.0,
segment-0.ts
#EXT-X-BYTERANGE:821000@0
large_archive.mp4
#EXT-X-ENDLIST

위는 개념 예시이며, 실제로는 fMP4·TS 조각 URL 전략과 함께 설계합니다.


2. 실전 구현

2.1 FFmpeg로 HLS 생성 (옵션 정리)

FFmpeg는 -f hls muxer로 HLS를 출력합니다. 주요 -hls_* 옵션을 용도별로 묶으면 다음과 같습니다. (버전에 따라 옵션명이 다를 수 있으므로 ffmpeg -h muxer=hls로 확인하십시오.)

옵션설명
-hls_time세그먼트 대략 길이(초) — 키프레임에 맞게 실제 길이는 달라질 수 있음
-hls_list_size플레이리스트에 유지할 세그먼트 개수; 0이면 VOD에 가깝게 전부 유지(라이브는 슬라이딩)
-hls_delete_threshold / -hls_flags delete_segments오래된 세그먼트 파일 삭제(디스크 관리)
-hls_base_url세그먼트 URL 앞에 붙는 베이스
-hls_segment_filename파일명 패턴
-hls_segment_typempegts | fmp4 — TS vs fMP4
-hls_fmp4_init_filenamefMP4 init 파일명
-hls_key_info_file암호화 키·URI 정보 파일(AES)
-hls_flagsindependent_segments, program_date_time, append_list, temp_file, round_durations플래그 조합
-hls_start_number_source시작 시퀀스 번호 정책
-master_pl_name / -hls_playlist_type / -streaming마스터 생성, event/vod타입
-force_key_frames (비디오) / -g (GOP)세그맞춤·키프레임 강제 — 세그먼트 길이와 직결

FFmpeg HLS muxer 문서에 나열되는 자주 쓰는 추가 옵션은 아래와 같습니다. (ffmpeg -h muxer=hls현재 바이너리의 목록을 확인하십시오.)

옵션설명
-start_number / -hls_start_number_sourceMEDIA-SEQUENCE·파일명 번호( generic / epoch / epoch_us / datetime )
-hls_allow_cacheEXT-X-ALLOW-CACHE에 대응(레거시 클라)
-hls_delete_thresholddelete_segments와 함께, 디스크에 얼마나 더 남겨둘지
-hls_segment_options내부 MPEG-TS muxer에 넘기는 key=value (콜론 이스케이프 주의)
-hls_enc / -hls_enc_key / -hls_enc_key_url / -hls_enc_ivkey_info_file 없이 AES 옵션을 직접 줄 때
-strftime / -strftime_mkdirhls_segment_filename날짜/시간 치환·하위 폴더 생성
-master_pl_name / -master_pl_publish_rate마스터 m3u8 이름·갱신 주기(다중 variant와 함께)
-method / -http_user_agentHLS를 HTTP PUT 등으로 원격에 쓸 때(오리진 업로드)
전역 -output_ts_offsetPTS 기준; -hls_flags program_date_time과 함께 쓰면 절대 시각 맞출 때가 많음

ABR(동일 소스, 두 품질 + 마스터) — FFmpeg 문서의 var_stream_map 예 패턴:

ffmpeg -i input.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
  -map 0:v -map 0:a -map 0:v -map 0:a -f hls \
  -var_stream_map "v:0,a:0 v:1,a:1" \
  -hls_time 4 -hls_list_size 6 -master_pl_name master.m3u8 \
  -hls_segment_filename 'seg_%v_%03d.ts' stream_%v.m3u8

해상도를 나누려면 filter_complex[v0][v1]을 만든 뒤 비디오 스트림만 -map하는 식으로 확장합니다. GOP·force_key_frameshls_time맞는지 항상 검증하십시오.

기본 fMP4 + 독립 세그먼트 예시:

ffmpeg -i input.mp4 -c:v libx264 -c:a aac -b:a 128k \
  -g 60 -keyint_min 60 -sc_threshold 0 \
  -f hls -hls_time 6 -hls_list_size 0 \
  -hls_segment_type fmp4 -hls_flags independent_segments \
  -hls_fmp4_init_filename init.mp4 \
  -master_pl_name master.m3u8 out_%v/stream.m3u8

주의: 다중 variant(ABR) 는 보통 variant_stream_map + -var_stream_map 패턴(FFmpeg 다중 스트림)로 한 번에 마스터 m3u8을 만들거나, 비트레이트별 인코딩을 나눈 뒤 마스터를 수동/스크립트로 합칩니다(아래 2.2).

2.2 적응형 비트레이트(ABR)

원리: 마스터에 여러 EXT-X-STREAM-INF가 있고, 클라이언트는 대역폭·버퍼·디코더를 보고 variant 전환합니다. RFC 8216 §4.3.5 BANDWIDTH, AVERAGE-BANDWIDTH, CODECS, RESOLUTION 등이 협상에 쓰입니다.

운영 체크리스트:

  • 비트레이트 래더GOP·키프레임 정책을 맞춰 스위칭 시점 품질 저하를 줄입니다.
  • 음성이 별도 EXT-X-MEDIA TYPE=AUDIO로 떨어지는 마스터인지, muxed인지에 따라 플레이어 설정이 달라질 수 있습니다.
  • 실측 대역선언 BANDWIDTH의 괴리가 크면 ABR이 과소/과다 추정합니다. 인코딩 후 실제 세그먼트 크기로 검산하십시오.

마스터 m3u8(개념):

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360,CODECS="avc1.4d001e,mp4a.40.2"
360p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720,CODECS="avc1.4d001f,mp4a.40.2"
720p/playlist.m3u8

2.3 AES-128 암호화

RFC 8216 §4.3.1 EXT-X-KEYMETHOD=AES-128 시 키 획득 URL(URI)이 공개됩니다. TLS(HTTPS) 로 키·세그メント를 내려 전송 구간을 보호하는 것이 일반적입니다.

#EXT-X-KEY:METHOD=AES-128,URI="https://example.com/key?kid=1",IV=0x...
  • KEY 회전: 세그먼트 구간마다 EXT-X-KEY를 바꾸면 키 로테이션이 됩니다(플레이어가 연속 EXT-X-KEY를 올바르게 처리해야 함).
  • FFmpeg: -hls_key_info_file로 키 경로·URL·(선택)IV 파일을 가리킵니다.

한계: 이는 샘플 AES 수준의 보호이며, 스크린 캡처·키 유출·클라이언트 측 복제는 막지 못합니다. 사업·라이선스 요구가 있으면 DRM을 검토합니다.

2.4 DRM(예: Apple FairPlay Streaming)

FairPlay는 Apple 생태계의 다른 스택입니다. HLS + FPS(FairPlay Streaming)·KSM(키 보안 모듈)·SPC·콘텐트 키 전달(라이선스·정책)이 Apple 문서 + 파트너 키 서버/packager 를 요구합니다. FFmpeg만으로 “완전한” FPS가 끝나는 경우는 드뭅니다. 실무 흐름은 대략:

  1. 콘텐트를 지원 툴로 HLS(보통 fMP4) + DRM 메타패키징
  2. KSM/라이선스 서버가 클라이언트(특히 Apple 단말) 정책에 맞게 키를 내려줌
  3. 플레이어는 AVPlayer(네이티브) 또는 지원 뷰어 사용

정리: OTT에서 FairPlay는 HLS “태그”만의 문제가 아니라 이종 서버·인증 문제입니다. 벤더 가이드(Microsoft Azure Media·AWS Elemental·Wowza 등)와 Apple FPS 문서를 동시에 보라고 말하는 편이 정직합니다.

2.5 CDN 배포 전략

  • 캐시 키: m3u8짧은 TTL 또는 캐시 무효가 쉬운지 확인; 세그먼트(.ts/.m4s)는 불변이라면Cache-Control: max-age + immutability에 유리.
  • CORS / HTTPS: fetch/XHR로 키·매니페스트를 가로채는 플레이어는 CORS가 필수롭습니다. Access-Control-Allow-Origin·자격 증명 정책을 m3u8·세그·키 모두에 맞출 것.
  • 쿼리스트링·서명 URL: ?token= 방식이면 CDN이 쿼리를 캐시 키에 포함하는지, 캐시 파열이 없는지 확인.
  • 지역 팁: HLS는 HTTP 캐시에 잘 맞는 편이나, 라이브는 오리진 부하·일관이 병목이 될 수 있어 멀티 CDN·쉴드(오리진 보호) 이야기로 이어집니다.

참고: HTTP 자체는 RFC 9110 (HTTP/1.1 식별자)캐시 관련 RFC와 함께 읽는 것이 좋습니다(조건부 GET, 206 Range 등).


3. 고급 주제: LL-HLS 및 저지연

저지연 HLS(Apple LL-HLS) 는 RFC 8216의 정식 “한 줄”이 아니라, IETF/업체 문서(Apple의 Low-Latency HLS 제안)에서 비롯된 확장입니다. RFC 8216확장 태그를 허용하므로(§1), 실제 태그·동작최소 요구EXT-X-SERVER-CONTROL·EXT-X-PART·EXT-X-RENDITION-REPORT스펙 문서(구버전/신버전) 대조가 필요합니다. 아래는 일반적 개념 정리입니다.

3.1 Partial Segments(파트)

세그를 하나의 큰 TS/fMP4 조각으로만 기다리지 않고, 인코딩·패키징부분(Part) 단위로 노출·요청될 수 있게 하여 인코더-플레이어 경로를 짧게 합니다. 효과는 GOP/세그 정책·CDN 캐시와 함께 나옵니다.

3.2 HTTP/2 Server Push

초기 LL-HLS 제안에 H2 push로 다음 리소스를 미리 밀어주는 아이디어가 등장했으나, HTTP/2 Server Push브라우저·서버에서 사용·비활성이 달랐고, RFC 9113 HTTP/2 시대에 push 자체가 “만능”이 아님이 널리 알려졌습니다. 2020년대 중반 이후 크롬은 HTTP/2 push를 제거하는 방향이었습니다(참고: Chrome Platform Status 등). 실서비스에서는 H2 push 가정 대신, Preload/힌트·캐시·오리진 배치를 우선하십시오.

3.3 Preload Hints

EXT-X-PRELOAD-HINT 는 “다음에 올 세그/파트”를 힌트로 알려, 클라이언트가 미리 요청·버퍼를 잡을 수 있게 합니다(구현·태그 뒤의 type·URI 규칙은 사용 중 패키저·hls.js 버전과 맞아야 합니다).

3.4 Blocking Playlist Reload

CAN-BLOCK-RELOAD=YES 등(서버 제어)과 함께, 플레이리스트 응답이 “아직 다음 파트가 없음”을 의미하도록 홀딩되면(긴 polling 대신) 빈번한 빈 200을 줄이는 저지연 패턴이 될 수 있습니다. 오리진지연동시 연결 한도를 동시에 봐야 합니다(타임아웃·503·캐시 비적합).

3.5 LL-HLS 관련 확장 태그(참조)

아래는 Low-Latency HLS 문서·업체 패키저가 널리 쓰는 태그·속성이며, 버전hls.js / Safari / tvOS 지원이 다릅니다. (RFC 8216 본문 목록에 없는 것이 많습니다 — 최신 IETF draft·Apple HLS Authoring 문서로 교차 확인하십시오.)

태그·속성용도(요지)
EXT-X-SERVER-CONTROLCAN-SKIP-UNTIL, CAN-BLOCK-RELOAD, HOLD-BACK서버/클라 협상
EXT-X-PART파트 단위 미디어·부분 INF
EXT-X-PRELOAD-HINT다음에 요청할 리소스 힌트
EXT-X-RENDITION-REPORT마스터 렌디션최소 MSEQ 등 ABR/동기 힌트
EXT-X-SKIPCAN-SKIP-UNTIL과 함께 이미 본 태그 생략
PART-TARGET / PART-HOLD-BACK파트 타깃 길이·최대 hold-back(재생)

RFC 역할: HLS “저지연”의 권위는 (1) 기본 RFC 8216 + (2) 사용 툴·클라이언트가 구현한 LL-HLS 확장 사양(Apple 문서, IETF draft 이력)을 함께 보아야 합니다.


4. 최적화

4.1 세그먼트 길이

  • 짧을수록(1~2s): ABR·시킹·라이브 지연은 줄어듦. 대신 요청 횟수·m3u8 갱신·캐시 미스 비용이 늘 수 있음.
  • 길게(6~10s): 안정·캐시·오리진 부하엔 유리. 라이브 지연·Zapping 느낌은 늘 수 있음.

실무: 인코딩 GOP = 세그 정수 배 를 맞추지 않으면, 짧은 세그로 갈수록 비정렬·끊김이 드러납니다.

4.2 플레이리스트 길이(슬라이딩 윈도)

라이브에서 hls_list_size 또는 “창에 남는 URI 개수”를 너무 짧게 잡으면, 네트워크 지터·재시도흔적이 사라진 URL을 요청하는 일이 늘 수 있습니다. 너무 길면 “라이브” 지연이 늘고 스토리지·플레이리스트 파싱 비용이 늘어납니다. 2×~3× 타겟듀레이션 정도 버퍼는 보통 재생 안정에도 도움이 됩니다(단말별로 다름).

4.3 Prefetch 전략

  • hls.js: 내부 loader·buffer 설정, 높은 품질 선행 fetch (대역 여유일 때) 등 — AbrController· API에 따라 버전별 차이.
  • CDN: preload-hint·쿠키/토큰·CORS다음 세그까지 일관되는지(미리 401/403 나면 오히려 역효과).

4.4 버퍼링 최소화(균형)

  • ABR지나치게 낮은 rung에서 멈추지 않게 BANDWIDTH·AVERAGE리얼에 맞출 것.
  • TLS RTT·DNS·TTFBHLS만 만져서는 한계; 엣지·HTTP/2·HTTP/3·0-RTT(주의: 보안/멱등)스택 논의.
  • 서버/오리진: m3u8 304·If-None-Match (구현·CDN 마다) 검토.

5. 브라우저 구현

5.1 hls.js (MSE)

원리: MSE( Media Source Extensions )로 fMP4sourceBuffer에 붙어 넣는 방식(코덱/컨테이너 지원은 브라우저·플랫폼 제약). hls.js는 HLS 매니페스트를 파싱하고 세그/파트fetch·appends 합니다(공식 문서: hls.js README).

최소 예시(개념):

<video id="v" controls playsinline></video>
<script type="module">
  import Hls from 'https://esm.sh/hls.js@1';

  const video = document.getElementById('v');
  const src = 'https://example.com/hls/master.m3u8';

  if (Hls.isSupported()) {
    const hls = new Hls({
      // 예: ABR, 버퍼(버전/환경에 따라 키 이름 확인)
      maxBufferLength: 30,
      maxMaxBufferLength: 60
    });
    hls.loadSource(src);
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED, () => video.play().catch(() => {}));
    hls.on(Hls.Events.ERROR, (e, data) => {
      if (data.fatal) {
        if (data.type === Hls.ErrorTypes.NETWORK_ERROR) hls.startLoad();
        else if (data.type === Hls.ErrorTypes.MEDIA_ERROR) hls.recoverMediaError();
      }
    });
  } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    video.src = src; // iOS 사파리 등(네이티브)
  }
</script>

핵심 API·이벤트(버전 1.x 기준, 이름은 Release Notes 확인):

  • Hls.isSupported(): MSE·코덱 가용
  • loadSource / attachMedia
  • MANIFEST_PARSED, LEVEL_SWITCHED, FRAG_LOADED
  • ERRORfatalstartLoad / recoverMediaError / destroy 분기
  • config: maxBuffer*, liveSyncDurationCount, (LL) lowLatency 관련·part·partHoldBackhls.js 문서/CHANGELOG 권장

5.2 Video.js + HLS

videojs-http-streaming (VHS) 또는 hls.js 연동으로 씁니다. Video.js 7+ 내장 VHS는 HLS(일부) / DASHVHS(구 http-streaming) 쪽에서 처리합니다. fMP4·HEVC 등 시나리오엔 hls.js가 필수로 이야기될 수 있으므로, 지원 매트릭스콤보를 고릅니다.

VHS 기본(번들·타입·재생):

<link href="https://vjs.zencdn.net/8.10.0/video-js.min.css" rel="stylesheet" />
<video id="p" class="video-js" controls playsinline
  data-setup='{"html5": {"hls": {"overrideNative": true}}}'>
</video>
<script src="https://vjs.zencdn.net/8.10.0/video.min.js"></script>
<script>
  const p = videojs('p', { controls: true });
  p.src({ type: 'application/x-mpegURL', src: 'https://example.com/hls/master.m3u8' });
  p.ready(() => p.play().catch(() => {}));
  p.on('error', () => { /* VHS: network, manifest, mediasource 등 코드 분기 */ });
</script>

overrideNativeiOS에서 네이티브 HLS 대신 MSE·VJS 경로로 태울지 정책에 따라 씁니다(전력·호환·DRM 이슈).

5.3 Safari 네이티브 HLS

macOS/iOS Safari·기본 AVPlayer 계열은 HLS를 네이티브로 재생합니다(보통 MSE 불필요). <video src="...m3u8">·HLS in Safari Apple Doc 륥 참고.

  • FairPlay + FPS 경로가 다를 수 있음(키·정책·EME(Encrypted Media Extensions) 수준).
  • 인라인 재생: iOS playsinline 속성 등.
  • CORS — 네이티브 다운로드는 브라우저가 직접; 그래도 인증/쿠키 정책은 맞아야 함.

5.4 에러 핸들링(공통)

유형원인(예)대응
네트워크(404/0 byte)세그삭제·캐시오염·URL 만료EXT-X-MEDIA-SEQUENCE·슬라이딩엣지 캐시·원본 일치
CORSm3u8만 헤더, 세그차단Access-Control-Allow-Origin 전 자산
401/403토큰 만료갱신·쿼리 동기
MEDIA_ERR_DECODE코덱·fMP4·SPS 불일치CODECS·인코딩 통일
스톨(멈춤)버퍼·GOP· 점프ABR 키회전·DISCONTINUITY 처리

hls.js는 FATAL일 때 recover/destroy·user gesture play() 재시도·퀄리티 캡을 조합하는 패턴이 흔합니다.


6. 정리

HLS는 HTTP·캐시와 잘 맞는 스택이지만, “m3u8 몇 줄”로 끝이 아니라 세그/키/마스터/ABR/DRM/지연이 한 파이프라인으로 묶입니다. RFC 8216기본선으로 두고, FFmpeg/패키저/플레이어지원 태그로 좁힌 뒤, 라이브·VOD·저지연 요구를 나누어 튜닝하십시오.

배포: 변경을 커밋·푸시한 뒤, 이 저장소의 경우 npm run deploy를 사용하므로(Cloudflare Pages 등) git push가 선행되도록 루틴을 맞추십시오.