HLS ダウンロードで音声と動画が分離している?修正方法
現代の HLS が音声と動画を別 manifest として配信する理由と、2026 年に単一の再生可能な MP4 にまとめる 3 つの方法。
HLS ストリームの「ダウンロード」ボタンを押したのに、ファイルが 2 つ出てきた —— 音のない video.mp4 と、映像のない audio.mp4。あるいはもっと悪いことに、無音の動画だけ手に入って、音声がまったく別の m3u8 にあることに気づかなかった。これはあなたのダウンロードツールの bug ではありません。これが現代の HLS の動作の仕方であり、市場のほぼすべての Chrome HLS 拡張は同じ方法で失敗します。
本稿ではなぜ現代の HLS が音声と動画を分離するのか、manifest が実際にどう見えるか、そして再生可能な MP4 に戻す3 つの実用的な方法を解説します —— 技術ユーザー向けの一行 FFmpeg コマンドから、誰でも使えるワンクリックの解決策まで。
現代の HLS の実際の姿
HLS の初期(Apple の 2009 年の元仕様、RFC 8216)、master playlist は media playlist のリストを指し、各 media playlist は音声と動画を一緒に多重化した .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 のようなセグメントが含まれ、連結して直接再生できました。1 ファイル、1 ストリーム、1 ダウンロード。
しかし今日、ほとんどの本番環境の HLS ストリームはそうではありません。現代の master playlist はこんな感じに見えます:
#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
動画 manifest は今や動画セグメントだけを含みます —— 音声はまったくありません。音声は完全に別の m3u8 に住み、EXT-X-MEDIA タグ(TYPE=AUDIO)で参照されます。プレーヤーが両方を並列でダウンロードし、同期してレンダリングします。
なぜ現代のすべてのストリームがこうするのか
分離は恣意的ではありません。すべての主要なストリーミングプラットフォームがこの方式に移行した具体的な理由が 4 つあります:
1. マルチオーディオトラック対応
英語、スペイン語、フランス語、ドイツ語、日本語の 5 つの音声トラックを持つ映画は、もし音声が動画に多重化されていたら、5× のストレージと 5× のエンコードコストが必要です。音声を独立した manifest に分離することで、プレーヤーは動画を再ダウンロードせずにトラックを切り替えられます。
2. 適応ビットレート効率
同じ音声トラックが 240p、480p、720p、1080p、4K の動画バリアントとペアになります。分離なしでは、各品質レベルが独自の音声コピーを必要とします。分離があれば、1 つの音声 manifest がすべての動画品質に対応します。
3. 暗号化ストリームの鍵管理
現代の HLS は AES-128 または SAMPLE-AES 暗号化を使います。音声と動画を分離することで、それぞれが独自の鍵ローテーションスケジュールを持てます。これは暗号化鍵が 60 秒ごとにローテーションされるライブストリームで重要です(DRM 隣接の保護として)。
4. CDN キャッシュ効率
音声セグメントは小さく(約 20-50 KB)、ほとんど変わりません。動画セグメントは大きく(約 1-5 MB)、帯域を支配します。分離することで、CDN は音声を積極的にキャッシュし、動画には別のキャッシュ戦略を取れます。
これは良い工学です。これがダウンロードを難しくしているのも事実です。
結合する 3 つの方法
方法 1:FFmpeg ワンライナー(技術ユーザー)
master playlist を読み、正しい音声 + 動画 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 でフィルタし、動画を再生します。最初に master playlist が、次に動画 media playlist、その次に音声 media playlist が読み込まれるのが見えます。それぞれを右クリック → URL をコピー → 上の FFmpeg コマンドに貼り付けます。
これは動きます。週に何度も使うと飽きます。
方法 2:yt-dlp / streamlink(半技術ユーザー)
yt-dlp も streamlink も master playlist を取り込み、音声/動画ペアリングを自動解決できます:
yt-dlp -f "bv*+ba/b" "https://example.com/master.m3u8"
-f "bv*+ba/b" フォーマット選択子は「最良動画 + 最良音声、分離が失敗したら最良単一ストリームにフォールバック」を意味します。これは一般的なケースを処理しますが、次のような場合に壊れます:
- 認証されたセッション(cookie)を必要とするストリーム
- Cloudflare や token ローテーション壁の後ろのストリーム
- ライブストリーム(yt-dlp はライブ HLS の録画が信頼できない)
公開 VOD なら最も簡単な CLI パスです。ログイン session 内の何かについては、方法 3 を参照。
方法 3:それを処理するブラウザ拡張機能(その他全員)
最初の 2 つの方法の根本的な問題は、m3u8 URL だけでは不十分ということです。現代のストリームは:
- 30-120 秒で期限切れになるセッション署名 URL
- 元 session のブラウザにあるが CLI ツールにはない cookie
- アンチボットシステムが検証するプレーヤー設定のカスタムリクエストヘッダー(
Origin、Referer) - Python の
requestsライブラリではなく、本物のブラウザに一致する TLS フィンガープリント
ブラウザ拡張機能は動画プレーヤーと同じ session 内に住みます。同じ cookie を見て、同じヘッダーを送り、同じ TLS フィンガープリントを継承します。ページ読み込み時に音声 manifest と動画 manifest の両方も見るので、URL をどこかにコピーすることなく自動的にペアリングできます。
これがまさに私たちが Video Downloader One-for-All を作った目的です。具体的には:
- 拡張機能がブラウジング中にネットワークの HLS manifest リクエストを監視
- master playlist を見たら、それを解析して音声 + 動画 manifest URI を記録
- ダウンロードをクリックすると、既存のブラウザ session を使って両方を並列で取得
- ブラウザ内で FFmpeg.wasm(FFmpeg の WebAssembly ビルド)を実行してストリームを単一の MP4 に muxing
- 結合されたファイルがダウンロードフォルダに着地、別ファイルなし
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.” (音声を録音せず、新しい録画を作り続けている。)
“我願意付費使用 希望作者趕快更新 不然視訊和音軌都是分開的”
これらの引用は Stream Recorder からのものです。Chrome ウェブストアで最もインストールされている HLS 拡張で、100 万以上のユーザーがいます。Stream Recorder は 2025-08-01 以降アップデートを受けていません。現代の HLS ストリームがそれを壊すのは、その manifest パーサーが音声/動画分離パターンより前のものだからです。これは Stream Recorder が動かない?2026 年最良の HLS / m3u8 代替 で詳しく説明しました。
他の最もインストールされている HLS 拡張(Live Stream Downloader、FetchV、Video Downloader Plus)は混在した成功度で分離を処理しています —— 一部は自動でペアリングし、一部は特定の品質を選んだときだけ、一部はまったく処理しません。
ダウンロードツールが分離を正しく処理しているか確認する方法
既知の分離 HLS ソースを選びます —— ほとんどのライブ放送プラットフォームがテストとして使えます。次に:
- テストしたい拡張でダウンロードを開始
- 完了したらファイルサイズを確認。5 分の 1080p 音声付き動画は 30-80 MB であるはず。約 25 MB の 2 ファイル、または 25 MB の無音ファイル 1 つが見えたら、分離が壊れています。
- VLC や任意のメディアプレーヤーでファイルを開く。音声が欠けているか同期外れなら、結合ステップが失敗しています。
- リップシンクと音声が一致した単一の再生可能ファイルが得られたら、分離は正しく処理されています。
私たちの拡張で同じテストができます:インストールして、以前失敗していたとわかっているストリームを見つけ、結果のファイルが音声付きで完全に再生できるか確認してください。
ライブストリームは?
ライブ HLS では分離はさらに重要です:
- 音声 manifest は動画 manifest と独立に更新(通常 6-10 秒ごと)
- 録画はドリフトなしで両方のバッファを同期させ続ける必要がある
- 一時停止/再開は両ストリームを一緒にシークする必要がある
私たちの拡張機能はこれを処理します —— ライブ専用の機能面については ライブ配信録画ページ を参照。上の基本的な FFmpeg コマンドはライブ HLS にも動きますが、-c copy を適切なバッファ設定に置き換える必要があり、URL ローテーション問題は実在し、境界でセグメントを失う可能性があります。
結合がずれた音声を生む場合
時折、結合は技術的には成功しても、音声が動画と数百ミリ秒ずれます。これは通常次を意味します:
- 音声と動画 manifest の開始時間が異なる —— プレーヤーはタイムスタンプ整列で処理するが、単純な連結はしない
- 一方が MPEG-TS タイムスタンプを使い、もう一方が fragmented MP4 タイムスタンプを使う —— 正規化が必要
FFmpeg 方式でこれが起こったら、-itsoffset 0.0(または小さな負の値)を追加して再 mux してください。私たちの拡張機能は mux 前に約 500 ms までのタイムスタンプスキューを自動補正します。それを超えるドリフトが見えたら、ソース URL を送ってください。確認します。
よくある質問
以前動いていたサイトでは分離は問題になりますか?
一部のストリーミングプラットフォームは依然として多重化されたセグメントを配信します —— 主に古いシステムや小規模 CDN です。それらでは、HLS ダウンロードツールはどれも 1 ファイルを生成します(manifest が 1 つしかないため)。しかし主要なプラットフォーム(放送ネットワーク、動画ホスティングサービス、ビデオオンデマンドポータル)はすべて 2022-2025 年の間に分離に移行しました。
なぜブラウザネイティブの「動画として保存」が動かないのですか?
<video> タグの source は master m3u8 です。ブラウザの「保存」は m3u8 をテキストファイルとしてダウンロードしようとし、解決された動画ではありません。manifest を解析してセグメントをダウンロードしないと、無用な 2 KB のテキストファイルが得られます。
画面録画でいいのでは?
できます、ただし:(1)動画を再エンコードして品質を失う;(2)OS の音声ループバック経由で音声を再録音し、ソースが 44.1 kHz でも 48 kHz になることが多い;(3)画面がソース解像度でない限り、フル解像度の動画を取得できない。直接 HLS ダウンロードは元の codec、解像度、音声品質をビット単位で保持します。
FFmpeg.wasm 方式はネイティブ FFmpeg と同じ速度ですか?
mux 操作(再エンコードなし)では、WebAssembly FFmpeg はネイティブ FFmpeg の約 80-90% の速度で動きます。30 分の動画ならブラウザで mux が約 5 秒、コマンドラインで約 4 秒 —— ノイズの範囲内です。再エンコードは遅いですが、mux 操作は再エンコードしません。
まとめ
現代の HLS における音声/動画分離は永続的な変化です。代替案が無駄である(ストレージ、エンコード、CDN キャッシュ)ため、ストリームは今後 10 年も音声と動画を分離し続けます。
それを扱う 3 つの方法:
- FFmpeg コマンドライン —— 動くが繰り返し使うと面倒
- yt-dlp / streamlink —— 公開 VOD には動く、認証とライブで壊れる
- 自動でペアリングして結合するブラウザ拡張機能 —— ログイン session 内のあらゆるものに動く
カテゴリ 3 にいるなら、Video Downloader One-for-All をインストール してください。音声/動画分離のケースこそ、この拡張機能が存在する具体的な理由です。