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
,如果视频加密,保存密钥;这是一个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 |-- ...