m3u8檔案合併處理
m3u8檔案合併處理
簡介
M3U8 是 Unicode 版本的 M3U,用 UTF-8 編碼。"M3U" 和 "M3U8" 檔案都是蘋果公司使用的 HTTP Live Streaming(HLS) 協議格式的基礎,這種協議格式可以在 iPhone 和 Macbook 等裝置播放。
HLS 的工作原理是把整個流分成一個個小的基於 HTTP 的檔案來下載,每次只下載一些。當媒體流正在播放時,客戶端可以選擇從許多不同的備用源中以不同的速率下載同樣的資源,允許流媒體會話適應不同的資料速率。在開始一個流媒體會話時,客戶端會下載一個包含元資料的 extended M3U (m3u8) playlist檔案,用於尋找可用的媒體流。
HLS 只請求基本的 HTTP 報文,與實時傳輸協議(RTP)不同,HLS 可以穿過任何允許 HTTP 資料通過的防火牆或者代理伺服器。它也很容易使用內容分發網路來傳輸媒體流。
簡單來說,m3u8是一個視訊格式,就是將一個視訊分成很多的小部分,這樣方便視訊的載入。
格式解析
完整的m3u8
檔案有三部分:
-
index.m3u8
,儲存視訊的基本資訊和分段檔案順序; -
key
,如果視訊加密,儲存金鑰; - data檔案,其他都是視訊的資料檔案。
這是一個index.m3u8
的內容,
-
#EXTM3U
,是檔案開始 -
#EXT-X-VERSION
,標識HLS的協議版本號; -
#EXT-X-TARGETDURATION
,表示每個視訊分段最大的時長(單位秒); -
#EXT-X-MEDIA-SEQUENCE
,表示播放列表第一個 URL 片段檔案的序列號; -
#EXT-X-PLAYLIST-TYPE
-
#EXT-X-KEY
,加密方式,這裡加密方式為AES-128
,同時指定IV
,在解密時需要; -
#EXTINF
,示其後 URL 指定的媒體片段時長(單位為秒); -
第8行指定媒體片段,媒體片段之前必須指定
EXTINF
標籤。
視訊融合
這裡使用python3
編寫,這裡所有的檔案都進行了加密,
import os import sys import time from Crypto.Cipher import AES def fileList(findex): rpath = os.path.dirname(os.path.realpath(findex)) name = rpath.split("\\")[-1] fi = open(findex, 'r') flag = False IV = None tl = [] for line in fi.readlines(): if line.startswith("#EXT-X-KEY"): # 如果存在 IV 則提取; if line.split(",")[-1].startswith("IV="): IV = line.split(",")[-1][5:] IV = bytes.fromhex(IV) if line.startswith("#EXTINF"): flag = not flag continue if flag: tmp = line.strip().split("/")[-1] tmp = os.path.join(rpath, tmp) tl.append(tmp) flag = not flag fi.close() fk = open(os.path.join(rpath, "key"), 'rb') key = fk.read() fk.close() return name, tl, key, IV def aes_decode(data, key, IV): # 如果沒有指定 IV 值,則直接使用 key 值 if not IV: IV = key cryptor = AES.new(key, AES.MODE_CBC, IV) plain_text = cryptor.decrypt(data) return plain_text def main(): fp = os.listdir() used = [s[:-4] for s in os.listdir("./result/")] for ind in fp: if not ind.isdigit(): continue if ind in used: continue try: name, fl, key, IV = fileList(os.path.join(ind, "index.m3u8")) except: print("-"*30) print("[-] Errot! file: ", ind) print("-"*30) continue print("[*] Begin process file: ", name) start = time.time() f = open(os.path.join("./result/", name+".mp4"), 'ab') for i in fl: with open(i, 'rb') as inf: data = inf.read() f.write(aes_decode(data, key, IV)) f.close() print("[+] Sucessfully! Cost time: ", time.time()-start) main()
使用程式的格式為:
./
|-- m3u8.py
|-- result
|-- 檔案1
|-- key
|-- index.m3u8
|-- data...
|-- 檔案2
|-- ...