← 返回部落格

如何只下載 HLS / m3u8 串流的某個片段(不是整個)

從 m3u8/HLS 串流中提取特定時間範圍,而非完整 VOD — ffmpeg 搜尋、分段索引數學及瀏覽器內剪輯方法。

你有一段三小時的 HLS VOD,想要第 47 到 52 分鐘的片段。下載整個清單(數百個分段、GB 級別的資料),然後在影片編輯器中修剪五分鐘 — 這不是有效的工作流程。HLS 由小型的獨立可取得的塊組成,這意味著沒有技術理由去下載時間窗口外的任何內容。你只需要找出哪些塊與你的時間窗口重疊。

這篇文章是這個系列中的技術深度文章。它假設你已經粗略了解什麼是 HLS 和 m3u8 — 如果你不了解,從如何下載 m3u8 / HLS 串流開始,了解完整的協議介紹,然後回來這裡。下面的目標更狹窄:給定一個媒體播放清單和一個 [start, end] 時間範圍,只獲取你需要的位元組。

我們將涵蓋三種方法 — 針對清單 URL 進行 ffmpeg 搜尋、範圍感知的 CLI 下載器,以及一個瀏覽器內剪輯擴充程式,該程式只會取得重疊的分段 — 加上使所有這些方法都能工作的分段索引數學。

為什麼分段下載是可能的

HLS 媒體播放清單本質上是一個帶有持續時間的有序分段列表。將真實的清單剝離下來,看起來像這樣:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD

#EXTINF:6.000,
segment000.ts
#EXTINF:6.000,
segment001.ts
#EXTINF:6.000,
segment002.ts
#EXTINF:6.000,
segment003.ts
...
#EXTINF:4.200,
segment842.ts
#EXT-X-ENDLIST

關鍵的行是 #EXTINF。它宣告了後面那個分段的確切持續時間。因為播放器按順序連接分段,分段 n 的開始時間就是它之前所有 #EXTINF 持續時間的總和。分段 0 涵蓋 [0, 6)、分段 1 涵蓋 [6, 12)、分段 2 涵蓋 [12, 18),以此類推。

這個特性就是讓部分下載成為可能的原因。要獲取窗口 [T_start, T_end),你不需要整個播放清單 — 你需要時間跨度與該窗口重疊的連續分段運行。第一個重疊分段之前的所有內容以及最後一個分段之後的所有內容都是你可以跳過的無用內容。

這立即產生了兩個結果:

  1. 你不能任意地在幀上進行切割。 分段開始於關鍵幀邊界(新的 IDR 幀在每個分段中開啟,在格式良好的串流中)。如果你想要複製專用、無重新編碼的提取,最便宜的切割點是分段邊界。更精細的準確度意味著需要重新編碼邊界分段。
  2. 數學只取決於 #EXTINF,不取決於分段檔案名稱、位元組偏移或 CDN 隱藏的任何東西。如果你能讀取媒體播放清單,你可以自己計算分段範圍。

將時間範圍對應到分段索引:一個實際例子

說分段是統一的 6 秒,你想要 10:00 到 15:00 — 即 [600s, 900s)

  • 第一個重疊分段索引:floor(600 / 6) = 100。分段 100 涵蓋 [600, 606)
  • 最後一個重疊分段索引:ceil(900 / 6) - 1 = 149。分段 149 涵蓋 [894, 900)

所以你需要分段 100 到 149 含其中 — 50 個分段、300 秒,而不是全部 843 個。如果你只連接這些,你會得到一個乾淨的五分鐘剪輯,精確地開始於 10:00(因為 600 是分段邊界),精確地結束於 15:00。

真實的播放清單很少有完全統一的持續時間 — 最後一個分段很短、廣告插入點重置時序、實時編碼器漂移。所以穩健的方法是不要除以常數 — 累積

# 虛擬代碼:時間範圍 -> 分段索引範圍
t = 0.0
first = last = None
for i, dur in enumerate(extinf_durations):
    seg_start, seg_end = t, t + dur
    if seg_end > T_start and first is None:
        first = i                      # 第一個到達窗口的分段
    if seg_start < T_end:
        last = i                       # 只要分段仍然重疊就繼續前進
    t = seg_end
# 獲取分段 [first .. last] 含其中

這個循環正是下面每個工具在內部所做的。方法之間的區別在於它們為你處理多少周圍的管道代碼 — 認證、關鍵提取、音頻/影片配對、URL 簽署。

方法 1:針對 m3u8 URL 進行 ffmpeg 搜尋

ffmpeg 本地理解 HLS,所以最直接的部分下載是將清單 URL 加上搜尋和持續時間交給它:

ffmpeg -ss 00:10:00 -t 00:05:00 -i "https://example.com/video/720p/playlist.m3u8" -c copy clip.mp4

-ss 是開始(搜尋到 10:00)、-t 是要捕獲的持續時間(5 分鐘),-c copy 直接流過數據包,不進行重新編碼。使用 -c copy,ffmpeg 只能在關鍵幀邊界切割,所以實際剪輯開始於在 10:00 時的關鍵幀或剛好在其之前 — 通常是我們例子中分段 100 的開始。這正是你想要的快速、無損抓取。

-ss 在 -i 之前 vs 之後

-ss 相對於 -i 的位置是這裡最重要的單一細節,它在速度和準確度之間進行權衡:

  • -ss -i 之前(輸入搜尋) — ffmpeg 在解碼前在多路分解器級別搜尋。對於 HLS,這意味著它可以跳過它根本不需要下載的整個分段。快速、網路便宜,是抓取片段的正確預設。準確度到最近的關鍵幀。
  • -ss -i 之後(輸出搜尋) — ffmpeg 從開始讀取、解碼,丟棄幀直到達到時戳。幀精確,但它必須拉出(通常解碼)達到你開始點之前的所有內容。對於從 3 小時 VOD 的 10:00 開始的剪輯,這很慢並違反了目的。

為了快速的分段下載,保持 -ss-i 之前。如果你在入點需要幀準確度,常見的做法是輸入搜尋到剛好在目標之前(快速)和輸出搜尋小餘數(準確),這意味著重新編碼頭部:

# 快速輸入搜尋到 ~9:58,然後幀精確修剪到 10:00,只重新編碼邊界
ffmpeg -ss 00:09:58 -i "https://example.com/video/720p/playlist.m3u8" \
  -ss 00:00:02 -t 00:05:00 -c:v libx264 -c:a aac clip.mp4

你失去了 -c copy 速度,但只是在你重新編碼的秒數上,不是整個剪輯。

老實說的注意事項

ffmpeg 對清單的工作是當串流可達且未簽署時的正確工具。當它不是這樣時,它變得很快變得麻煩:

  • 過期的簽署 URL。 許多 CDN 使用在 60–300 秒內過期的令牌簽署清單(有時每個分段)。如果你從 DevTools 複製 URL,而 ffmpeg 仍在通過長剪輯時令牌死亡,你會得到 403 中期下載。對於五分鐘的複製,這通常沒問題;對於任何更長的或你弄錯時序的任何東西,這是一個真正的問題。

  • AES-128 加密。 如果播放清單帶有 #EXT-X-KEY:METHOD=AES-128,URI="key.bin",ffmpeg 將自動獲取並應用密鑰 — 只要關鍵 URL 可通過你的裸 ffmpeg 呼叫所具有的請求上下文達成。如果關鍵端點需要你的裸 ffmpeg 呼叫不發送的 cookie 或標頭,解密失敗。

  • 分開的音頻和影片清單。 現代 HLS 通常將音頻和影片分成單獨的媒體播放清單。只搜尋影片清單給你一個無聲的剪輯。你必須同時傳遞兩個作為輸入並搜尋兩個:

    ffmpeg \
      -ss 00:10:00 -t 00:05:00 -i "https://example.com/video/720p/playlist.m3u8" \
      -ss 00:10:00 -i "https://example.com/audio/en/playlist.m3u8" \
      -c copy -bsf:a aac_adtstoasc clip.mp4

    (更多關於無聲剪輯失敗模式見HLS 下載:音頻和影片是分開的。)

  • Referer / 自訂標頭。 在原點上設定閘門的 CDN 需要明確傳遞標頭,例如 -headers "Referer: https://example.com/watch"。搞錯它,每個分段請求都會 403。

對於指令碼編寫,這些都不是交易破壞者 — 當你已經有 URL、標頭和密鑰排列好,想要可重複、可自動化的切割時,ffmpeg 是無可比擬的。當串流在登入或旋轉簽名後面時,這只是真正麻煩,因為你正在手動重建瀏覽器免費產生的請求上下文。

方法 2:範圍感知的 CLI 下載器(N_m3u8DL-RE、yt-dlp)

如果你想在分段/時間空間工作而不是在 ffmpeg 搜尋標誌中,專門的 HLS 下載器可以選擇播放清單的子集。

N_m3u8DL-RE 直接暴露了範圍選擇。它的 --custom-range 標誌接受時間或分段範圍,並只下載那些分段 — 這正是「獲取重疊運行」操作,為你完成:

# 時間範圍
N_m3u8DL-RE "https://example.com/master.m3u8" --custom-range "00:10:00-00:15:00" --save-name clip

# 或按分段索引
N_m3u8DL-RE "https://example.com/master.m3u8" --custom-range "100-149" --save-name clip

它也解決了主清單、配對音頻和影片軌道,並應用了 AES-128 密鑰,這消除了大部分的 ffmpeg 困擾。權衡是它是另一個要安裝的二進位檔案,其切割準確度是分段粒度 — 你得到整個分段,所以你的剪輯在每端卡在最近的分段邊界上。

yt-dlp 是更寬泛的工具,但其範圍支援更狹窄,值得坦誠。--download-sections 標誌適用於具有真實提取器的網站(最著名的是通過章節/時戳範圍的 YouTube):

yt-dlp --download-sections "*00:10:00-00:15:00" -f "bv*+ba/b" "https://www.example.com/watch?v=..."

但對於原始 .m3u8 URL--download-sections 經常回落到下載完整串流並使用 ffmpeg 進行修剪,因為 yt-dlp 的通用 HLS 處理並不總是進行本地分段範圍提取。所以你節省磁碟和修剪工作,但不一定是頻寬。在假設它只抓取了窗口之前,檢查它實際上獲取了什麼。

兩種工具都共享與裸 ffmpeg 相同的盲點:它們在公開、未簽署的串流上清楚地工作。指向認證牆或短期限簽署清單的它們,你回到手動從 DevTools 複製 cookies、標頭和新簽署的 URL。

方法 3:在瀏覽器中使用 OFA 進行剪輯(無 CLI,繼承會話)

上面的每種方法都共享一個根本問題:清單和分段是提供給特定認證的瀏覽器會話的,而命令列工具不是那個會話。你最終反向工程請求上下文 — cookies、Referer、簽署的查詢字串、關鍵端點的認證 — 並與在一分鐘內過期的令牌競速。

繞過這個的方法是在頁面內進行剪輯,在那裡會話已經存在。Video Downloader One-for-AllClip & Trim Download(在 v1.1.38、2026 年 6 月添加)正是這樣做的:

  1. 打開頁面並讓播放器正常加載串流。
  2. 打開 OFA 的剪輯視圖 — 你得到了檢測到的 HLS/DASH 串流的可搜尋預覽
  3. 將入點和出點拖到你的確切範圍(例如 10:00 → 15:00)。
  4. 下載。OFA 只獲取與你選擇範圍重疊的分段 — 運行本文頂部相同的累積和選擇邏輯 — 並將它們混合到單個 MP4。

因為它以 Chrome/Edge 擴充程式的身份在標籤內運行,它:

  • 繼承播放器的認證 — cookies、簽署的 URL 和 Referer 是頁面已經發送的任何東西,所以登入閘門和短期限串流無需你複製任何東西就可以工作。
  • 透明地處理 AES-128,使用頁面自己的請求上下文獲取密鑰。
  • 自動配對分開的音頻和影片清單,所以剪輯有聲音 — 不需要記住 -bsf:a aac_adtstoasc 咒語。
  • 只獲取你的窗口,不是整個 VOD,所以三小時串流的五分鐘剪輯下載大約五分鐘的資料。

Clip & Trim 在免費和付費計畫上都可用。切割準確度在邊界處是分段粒度的(與 N_m3u8DL-RE 相同的約束 — 複製專用提取只能在關鍵幀已經位於的位置切割),對於典型的 2–6 秒分段,這會讓你在你設置的標記幾秒內。如果你需要確切的幀入/出,在這裡取更大的剪輯並使用來自方法 1 的輸出搜尋 ffmpeg 模式在本地進行最終幀精確修剪。

基礎 HLS 引擎的產品詳情位於 HLS 下載器頁面,並用於捕獲實時(非 VOD)窗口,其中清單是滑動窗口而不是固定列表,見 live stream recorder

這也是平行指南如何下載影片的一部分為一般情況推薦的路徑,當你想要從長串流中獲得單一亮點時相同的方法適用 — 見如何下載 Twitch VOD 以了解該特定情況。

哪種方法,何時

方法需要 CLI處理認證/cookies處理 AES-128幀準確度只獲取範圍
ffmpeg -ss/-t手動(標頭/cookies 手工)是(如果關鍵 URL 可達)預設關鍵幀;使用重新編碼達成幀精確是(使用輸入搜尋)
N_m3u8DL-RE --custom-range手動分段粒度
yt-dlp --download-sections部分(提取器依賴)變化;通常在完整提取後修剪只有當提取器進行本地範圍時
OFA Clip & Trim是(繼承頁面會話)是(透明)分段粒度

誠實的總結:

  • ffmpeg 是在公開或自助流上進行指令碼編寫和自動化的最佳工具 — 可重複、可組合、無 GUI,你控制每個標誌。當你與認證牆或 60 秒令牌對抗時,它是最差的工具。
  • N_m3u8DL-RE 是當你想要明確範圍選擇而不是 ffmpeg 的搜尋標誌微妙性,且串流未被鎖定時的最好 CLI 中等方案。
  • OFA Clip & Trim 是當串流需要你的登入或分發快速過期的簽署 URL 時,或當你根本不想接觸終端機時的最佳工具 — 因為它根本不會離開已認證的瀏覽器會話。

關於權利和 DRM 的說明

只下載你有權保存的內容 — 你自己的上載、你有許可使用的材料或內容源的條款允許的內容。為了清楚起見:本整篇文章涉及清晰(或 AES-128 加密)HLS,它是可解密的,因為密鑰被傳遞給播放器。由 Widevine、PlayReady 或 FairPlay 保護的串流是另一回事 — 內容密鑰永遠不會離開硬體支持的 CDM,沒有瀏覽器內擴充程式或 CLI 可以提取它,OFA 不支援它們。如果你看到那些,本文中的分段下載技術不適用。

結論

分段下載是可能的,因為 HLS 播放清單是帶時序的分段列表:求和 #EXTINF 持續時間,找到與你的 [start, end] 窗口重疊的連續運行,只獲取那個運行。ffmpeg、N_m3u8DL-RE 和 yt-dlp 都在幕後進行這個數學計算,在開放串流上非常出色 — 為指令碼編寫和批量工作選擇它們。當串流在登入後面或其 URL 在秒內過期時,摩擦力不是數學,而是重現瀏覽器的會話 — 這正是為什麼使用 Video Downloader One-for-All 在頁面內進行剪輯是所有認證牆內容的最小阻力路徑。