HLS 다운로드 시 음성과 영상이 분리되어 있나요? 해결 방법은 다음과 같습니다
2026년 HLS 스트림 음성·영상 분리 이유 및 단일 MP4로 다운로드하는 3가지 방법
HLS 스트림에서 “다운로드”를 눌렀는데 두 개의 파일이 나왔다면 — video.mp4는 소리가 없고, audio.mp4는 화면이 없다. 혹은 더 나쁜 경우, 음성 없는 영상만 받았고 완전히 다른 m3u8에 음성이 있다는 것을 나중에 깨달았을 수도 있습니다. 이것은 다운로더의 버그가 아닙니다. 현대 HLS가 작동하는 방식이며, 오늘날 시장의 거의 모든 Chrome HLS 확장 프로그램이 같은 방식으로 실패합니다.
이 글에서는 현대 HLS가 왜 음성과 영상을 분리하는지, 실제 매니페스트가 어떻게 생겼는지, 그리고 이를 다시 하나의 재생 가능한 MP4로 병합하는 3가지 실용적인 방법을 설명합니다. 기술 사용자를 위한 한 줄의 FFmpeg 명령어부터 모든 사람을 위한 원클릭 솔루션까지 다룹니다.
현대 HLS는 실제로 어떻게 생겼나요
HLS 초창기(Apple의 2009년 원본 스펙, RFC 8216)에서는 마스터 플레이리스트가 미디어 플레이리스트 목록을 가리켰고, 각각의 미디어 플레이리스트는 이미 음성과 영상이 함께 들어간 .ts 세그먼트를 포함했습니다:
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=1280000,RESOLUTION=720x480
720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2560000,RESOLUTION=1280x720
1080p.m3u8
연결된 각 m3u8은 seg001.ts 같은 세그먼트를 포함했고, 이를 연결해서 직접 재생할 수 있었습니다. 하나의 파일, 하나의 스트림, 하나의 다운로드였습니다.
이것은 오늘날의 대부분의 프로덕션 HLS 스트림의 모습이 아닙니다. 현대 마스터 플레이리스트는 더 이렇게 생겼습니다:
#EXTM3U
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="English",DEFAULT=YES,URI="audio/eng/playlist.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Spanish",URI="audio/spa/playlist.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English",URI="subtitles/eng.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=1280000,RESOLUTION=720x480,CODECS="avc1.4d401e",AUDIO="aac",SUBTITLES="subs"
video/720p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2560000,RESOLUTION=1280x720,CODECS="avc1.4d401f",AUDIO="aac",SUBTITLES="subs"
video/1080p/playlist.m3u8
이제 영상 매니페스트는 영상 세그먼트만 포함합니다 — 음성이 전혀 없습니다. 음성은 EXT-X-MEDIA 태그(TYPE=AUDIO)에서 참조하는 완전히 별개의 m3u8에 있습니다. 플레이어는 이 둘을 병렬로 다운로드하고 동기화하여 렌더링해야 합니다.
모든 현대 스트림이 이렇게 하는 이유
분리는 임의적이지 않습니다. 모든 주요 스트리밍 플랫폼이 이것으로 이동한 네 가지 구체적인 이유가 있습니다:
1. 다중 음성 트랙 지원
영어, 스페인어, 프랑스어, 독일어, 일본어 음성 트랙이 있는 영화는 음성이 영상에 함께 들어가 있다면 저장 공간과 인코딩 비용이 5배 필요합니다. 음성을 자체 매니페스트로 분리하면 플레이어가 영상을 다시 다운로드하지 않고도 트랙을 전환할 수 있습니다.
2. 적응형 비트레이트 효율성
동일한 음성 트랙을 240p, 480p, 720p, 1080p, 4K 영상 변형과 함께 사용할 수 있습니다. 분리가 없으면 모든 품질 수준이 자신의 음성 복사본을 필요로 합니다. 분리가 있으면 하나의 음성 매니페스트가 모든 영상 품질에 사용됩니다.
3. 암호화된 스트림 키 관리
현대 HLS는 AES-128 또는 SAMPLE-AES 암호화를 사용합니다. 음성과 영상을 분리하면 각각이 자신의 키 로테이션 일정을 가질 수 있습니다. 이것은 암호화 키가 DRM 인접(하지만 완전한 DRM은 아닌) 보호를 위해 60초마다 로테이션하는 라이브 스트림에 중요합니다.
4. CDN 캐시 효율성
음성 세그먼트는 작습니다(~20-50 KB)이고 거의 변경되지 않습니다. 영상 세그먼트는 큽니다(~1-5 MB)이고 대역폭을 지배합니다. 이들을 분리하면 CDN이 음성을 공격적으로 캐시하고 영상을 다른 캐시 전략으로 스트리밍할 수 있습니다.
이것은 좋은 엔지니어링입니다. 또한 다운로드를 더 어렵게 만드는 것이기도 합니다.
다시 병합하는 방법: 3가지 접근
접근법 1: FFmpeg 한 줄 명령어(기술 사용자)
마스터 플레이리스트를 읽고 올바른 음성 + 영상 URI를 식별할 수 있다면, FFmpeg는 재인코딩 없이 한 번에 병합합니다:
ffmpeg \
-i "https://example.com/video/1080p/playlist.m3u8" \
-i "https://example.com/audio/eng/playlist.m3u8" \
-c copy \
-bsf:a aac_adtstoasc \
output.mp4
플래그:
-c copy— 스트림 복사, 재인코딩 없음, 손실 없고 빠름-bsf:a aac_adtstoasc— 음성이 MPEG-TS 내부의 AAC일 때 필수, 없으면 iOS/Safari가 결과 MP4를 재생할 수 없음
URL을 찾으려면 Chrome DevTools를 열고, Network 탭으로 이동하고, m3u8으로 필터링한 후 영상을 재생하세요. 마스터 플레이리스트가 먼저 로드되고, 그다음 영상 미디어 플레이리스트, 그다음 음성 미디어 플레이리스트가 로드되는 것을 볼 수 있습니다. 각각 마우스 우클릭하고, URL 복사한 후, 위의 FFmpeg 명령어에 붙여넣으세요.
작동합니다. 또한 일주일에 한 번 이상 수행하면 느립니다.
접근법 2: yt-dlp / streamlink(반기술 사용자)
yt-dlp와 streamlink 모두 마스터 플레이리스트를 수집할 수 있고 음성/영상 쌍을 자동으로 확인합니다:
yt-dlp -f "bv*+ba/b" "https://example.com/master.m3u8"
-f "bv*+ba/b" 포맷 선택자는 “최고 영상 + 최고 음성, 분리가 실패하면 최고 단일 스트림으로 폴백”을 의미합니다. 일반적인 경우를 처리하지만 다음에서 실패합니다:
- 인증된 세션(쿠키)이 필요한 스트림
- Cloudflare 또는 토큰 로테이션 벽 뒤의 스트림
- 라이브 스트림(yt-dlp는 라이브 HLS를 안정적으로 기록하지 않음)
공개 접근이 가능한 VOD의 경우 이것이 가장 쉬운 CLI 경로입니다. 로그인된 세션 내의 모든 것의 경우 접근법 3을 참조하세요.
접근법 3: 이를 처리하는 브라우저 확장 프로그램(그 외 모든 사람)
처음 두 접근법의 근본적인 문제는 m3u8 URL만으로는 충분하지 않다는 것입니다. 현대 스트림은 다음을 사용합니다:
- 30-120초 내에 만료되는 세션별 서명된 URL
- 원래 브라우저 세션은 갖지만 CLI 도구는 갖지 않는 쿠키
- 플레이어가 설정하는 커스텀 요청 헤더(
Origin,Referer) — 안티봇 시스템이 검증함 - 실제 브라우저와 일치하지만 Python
requests라이브러리와는 일치하지 않는 TLS 지문
브라우저 확장 프로그램은 영상 플레이어와 같은 세션 내에 있습니다. 동일한 쿠키를 보고, 동일한 헤더를 보내고, 동일한 TLS 지문을 상속받습니다. 또한 페이지가 음성 매니페스트와 영상 매니페스트를 로드할 때 둘 다 보므로, URL을 어디에도 복사하지 않고도 자동으로 쌍을 만들 수 있습니다.
이것이 우리가 Video Downloader One-for-All을 만든 이유입니다. 구체적으로:
- 확장 프로그램은 탐색 중에 HLS 매니페스트 요청에 대한 네트워크를 모니터링합니다
- 마스터 플레이리스트를 보면 이를 파싱하고 음성 + 영상 매니페스트 URI를 기록합니다
- 다운로드를 클릭하면 기존 브라우저 세션을 사용하여 둘 다 병렬로 가져옵니다
- FFmpeg.wasm(FFmpeg의 WebAssembly 빌드)을 브라우저 내에서 실행하여 스트림을 단일 MP4로 먹싸이(mux)합니다
- 병합된 파일이 다운로드 폴더에 도착하고, 별개의 파일은 없습니다
DevTools 없음, 명령줄 없음, 만료된 URL 없음. 전체 파이프라인이 탭에서 실행되므로 영상의 어느 부분도 머신을 떠나지 않습니다.
다른 대부분의 확장 프로그램이 실패하는 이유
Chrome 웹 스토어에서 HLS 확장 프로그램의 최근 1별 리뷰를 읽으면, 음성-영상 분리 문제가 반복적으로 나타납니다:
“Splits into audio and video streams and constantly opens new recordings ad infinitum.”
“It’s not recording audio and is constantly creating new recordings.”
“我願意付費使用 希望作者趕快更新 不然視訊和音軌都是分開的” (“I’d pay to use it — please update soon, otherwise audio and video are separated.”)
이 인용문들은 Chrome 웹 스토어에서 가장 설치된 HLS 확장 프로그램인 Stream Recorder의 것입니다(100만 명 이상의 사용자). Stream Recorder는 2025-08-01 이후로 업데이트를 받지 않았습니다. 현대 HLS 스트림은 이것을 깨뜨립니다. 그 매니페스트 파서가 음성/영상 분리 패턴보다 먼저 나왔기 때문입니다. 우리는 Stream Recorder Not Working in 2026? Best HLS/m3u8 Alternative에서 이것을 상세히 다루었습니다.
다른 상위 설치 HLS 확장 프로그램들(Live Stream Downloader, FetchV, Video Downloader Plus)은 분리를 혼합 성공으로 처리합니다 — 일부는 자동으로 쌍을 만들고, 일부는 특정 품질을 선택할 때만, 일부는 전혀 그렇지 않습니다.
다운로더가 분리를 올바르게 처리하는지 확인하는 방법
알려진 분리 HLS 소스를 선택하세요 — 대부분의 라이브 방송 플랫폼은 테스트로 작동합니다. 그다음:
- 테스트하려는 확장 프로그램으로 다운로드를 시작합니다
- 완료되면 파일 크기를 확인하세요. 5분 1080p 영상(음성 포함)은 30-80 MB이어야 합니다. ~25 MB 파일 두 개 또는 25 MB 음성 없는 파일 하나를 보면 분리가 깨진 것입니다.
- VLC 또는 다른 미디어 플레이어에서 파일을 열어보세요. 음성이 없거나 동기화되지 않으면 병합 단계가 실패한 것입니다.
- 음성과 입 움직임이 일치하는 단일 재생 가능한 파일을 받으면 분리가 올바르게 처리된 것입니다.
우리 확장 프로그램으로도 같은 테스트를 할 수 있습니다: 설치하고, 예전에 실패했던 스트림을 찾고, 결과 파일이 음성과 함께 끝까지 재생되는지 확인하세요.
라이브 스트림은 어떻게 되나요?
라이브 HLS의 경우 분리가 훨씬 더 중요합니다. 왜냐하면:
- 음성 매니페스트가 영상 매니페스트와 독립적으로 업데이트됩니다(일반적으로 6-10초마다)
- 기록은 드리프트 없이 두 버퍼를 동기화 상태로 유지해야 합니다
- 일시 중지/재개는 두 스트림을 함께 검색해야 합니다
우리 확장 프로그램은 이를 처리합니다 — Live Stream Recorder 페이지에서 라이브 관련 기능을 참조하세요. 위의 기본 FFmpeg 명령어도 -c copy를 적절한 버퍼 설정으로 바꾸면 라이브 HLS에 대해 작동하지만, URL 로테이션 문제는 실제이며 경계에서 세그먼트를 잃을 가능성이 높습니다.
병합이 음성을 동기화하지 않은 경우
때때로 병합이 기술적으로는 성공하지만 음성이 영상과 몇 백 밀리초 동기화되지 않습니다. 이것은 일반적으로 다음을 의미합니다:
- 음성 매니페스트와 영상 매니페스트의 시작 시간이 다릅니다 — 플레이어는 타임스탐프 정렬로 이를 처리하지만, 순진한 연결은 그렇지 않습니다
- 하나의 스트림은 MPEG-TS 타임스탐프를 사용하고 다른 하나는 단편화된 MP4 타임스탐프를 사용합니다 — 정규화가 필요합니다
FFmpeg 접근법에서 이것이 발생하면 -itsoffset 0.0(또는 작은 음수 값)을 추가하고 재먹싸이(re-mux)하세요. 우리 확장 프로그램은 먹싸이 전에 ~500ms까지의 타임스탐프 스큐를 자동으로 수정합니다. 그 이상의 드리프트를 보면 우리에게 소스 URL을 보내세요 확인해드리겠습니다.
일반 질문
예전에 작동했던 사이트에서 분리된 음성과 영상이 문제가 될까요?
일부 스트리밍 플랫폼은 여전히 먹싸이된 세그먼트를 제공합니다 — 주로 오래된 시스템과 소규모 CDN. 그러한 경우 모든 HLS 다운로더는 하나의 매니페스트만 있으므로 하나의 파일을 생성합니다. 하지만 주요 플랫폼(방송 네트워크, 비디오 호스팅 서비스, 주문형 비디오 포털)은 모두 2022-2025 사이에 분리로 이동했습니다.
브라우저 기본 “비디오로 저장”이 작동하지 않는 이유는?
<video> 태그의 소스는 마스터 m3u8입니다. 브라우저의 “다른 이름으로 저장”은 해결된 영상이 아닌 m3u8을 텍스트 파일로 다운로드하려고 시도합니다. 매니페스트를 파싱하고 세그먼트를 다운로드하지 않으면 쓸모없는 2KB 텍스트 파일을 받습니다.
대신 화면을 기록할 수 있을까요?
할 수 있지만: (1) 영상을 재인코딩하여 품질을 잃습니다; (2) OS 오디오 루프백을 통해 음성을 다시 기록하는데, 원본이 44.1kHz일 때 종종 48kHz입니다; (3) 화면이 원본 해상도가 아니면 전체 해상도 영상을 캡처할 수 없습니다. 직접 HLS 다운로드는 원본 코덱, 해상도, 음성 품질을 비트 단위로 보존합니다.
FFmpeg.wasm 접근법이 네이티브 FFmpeg만큼 빠를까요?
먹싸이 작업(재인코딩 없음)의 경우 WebAssembly FFmpeg은 네이티브 FFmpeg의 대략 80-90% 속도로 실행됩니다. 30분 영상의 경우 이는 브라우저에서 먹싸이가 ~5초, 명령줄에서는 ~4초에 완료된다는 의미입니다 — 충분히 무시할 수 있는 수준입니다. 재인코딩의 경우 더 느리지만 먹싸이 작업은 재인코딩을 하지 않습니다.
결론
현대 HLS의 음성-영상 분리는 영구적인 변화입니다. 스트림은 다음 10년 동안 음성과 영상을 분리할 것입니다. 왜냐하면 대안들은 낭비적입니다(저장 공간, 인코딩, CDN 캐시).
다루기 위한 3가지 방법:
- FFmpeg 명령줄 — 작동하지만 반복 사용 시 지루움
- yt-dlp / streamlink — 공개 VOD에 작동하고, 인증 및 라이브에서 실패
- 자동으로 쌍을 만들고 병합하는 브라우저 확장 프로그램 — 로그인된 세션의 모든 것에 작동
3번 카테고리에 속한다면 Video Downloader One-for-All을 설치하세요. 음성-영상 분리 케이스가 확장 프로그램이 존재하는 구체적인 이유입니다.