m3u8解析需逐行读取并精准识别#ext-x-stream-inf:和#extinf:行;正确提取bandwidth、resolution等属性;安全拼接base url与相对路径;处理utf-8 bom及换行符;校验url合法性。

识别 M3U8 文件中的 EXT-X-STREAM-INF 和 EXTINF 行
M3U8 是 UTF-8 编码的文本文件,关键信息藏在以 #EXT-X-STREAM-INF:(多清晰度主播放列表)或 #EXTINF:(普通分片列表)开头的行里。解析时不能只靠 std::string::find("#") 粗暴跳过注释——很多播放器会把元数据写在注释行末尾,比如 #EXT-X-STREAM-INF:BANDWIDTH=1280000,RESOLUTION=1280x720,后面可能紧跟空格和 URL。
实操建议:
- 逐行读取(
std::getline),跳过空行和纯#行 - 对含
#EXT-X-STREAM-INF:的行,用std::string::find_first_of(" \t")找到属性结束位置,再从该位置往后找第一个非空白字符——它大概率是子列表 URL - 对含
#EXTINF:的行,下一行才是 ts 文件路径,但要防“下一行为空”或“下一行仍是注释”的情况(有些非法 M3U8 会这样写)
安全拼接 base URL 与相对路径
绝大多数 M3U8 返回的是相对路径(如 chunk_0001.ts 或 sub/playlist.m3u8),而 base URL 来自原始请求地址(如 https://example.com/live/index.m3u8)。直接字符串拼接 base + "/" + path 会出错:base 末尾可能已有斜杠、path 可能以 / 开头、path 可能含 ../。
实操建议:
- 用
std::string::rfind("/")找 base 最后一个/,截取到该位置得到目录前缀(注意处理https://host/这种末尾带/的情况) - 若 path 以
http://或https://开头,直接用,不拼接 - 若 path 以
/开头,说明是绝对路径,应替换 base 的 host+path 部分(需先解析 base 的 scheme+host) - 否则视为相对路径,执行
prefix + path;拼接后用简单规则清理//和/../(不要引入完整 URI 库,多数嵌入场景不需要 RFC 3986 全兼容)
提取 BANDWIDTH 和 RESOLUTION 等关键属性
#EXT-X-STREAM-INF: 后的属性是逗号分隔的 KEY=VALUE 对,但 VALUE 可能带引号(如 CODECS="avc1.42E01E,mp4a.40.2")、空格(如 NAME="High Quality"),甚至等号本身(极少见,但规范允许 VALUE 包含未转义等号)。硬切逗号会崩。
实操建议:
- 从冒号后开始扫描,跳过首尾空白
- 每次找下一个逗号前,先检查当前位置是否在引号内(维护一个
in_quote布尔态,遇"就翻转) - 遇到不在引号内的逗号才分割;KEY 用
=切,VALUE 去掉两端引号和空白 - 特别注意
BANDWIDTH是必选字段,类型为整数;RESOLUTION格式固定为WxH(如1920x1080),可直接std::sscanf(val.c_str(), "%dx%d", &w, &h)
处理 UTF-8 BOM 和换行符兼容性问题
Windows 记事本保存的 M3U8 常带 UTF-8 BOM(0xEF 0xBB 0xBF),Linux/macOS 生成的则多为 LF 换行,而部分 CDN 返回 CRLF。C++ std::ifstream 默认按系统换行处理,读到 BOM 会导致首行解析失败(比如把 #EXTM3U 读成 \xEF\xBB\xBF#EXTM3U)。
实操建议:
- 打开文件后立即用
peek()检查前三个字节是否为 BOM,是则ignore(3) - 读取时统一用
std::getline(in, line),它自动处理 CRLF/LF,无需手动 strip\r - 所有字符串比较(如
line.substr(0, 8) == "#EXTM3U")前,确保已 trim 行首尾空白(BOM 后可能有空格) - 避免用
std::string::c_str()直接传给 C 风格函数处理——UTF-8 多字节字符会让strlen算错长度,改用line.length()
真正麻烦的不是语法解析,而是 M3U8 实际部署中大量存在的“非标写法”:属性值不加引号、URL 含空格、跨域重定向后的 base URL 变化、以及某些直播源动态插入的 #EXT-X-DISCONTINUITY-SEQUENCE 等冷门标签——这些不会报错,但会让拼出的 URL 404 或解码失败。建议在提取 URL 后加一层 std::string::find("://") != std::string::npos 快速校验是否拼成了合法 URI。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











