资讯动态

videojs v10 源代码系列解读:35 · HLS 解析器:multivariant 与 media playlist

发布时间:2026/10/2 6:57:22 来源:尧图企业网站定制
进入卷五的领域部分。这篇拆spf/src/media/hls/的三个纯函数解析器——multivariantmaster playlist、media playlist、属性字符串。它们是「文本 → 类型化 Presentation/Track/Segment」的转换层零依赖、可直接测。最有意思的是 multivariant 解析里那个跨音频组的去重算法——HLS 的笛卡尔积坑被它漂亮地解掉了。解析器的定位SPF 的解析器在media/hls/不是playback/——它们是纯领域逻辑不碰 DOM、不碰网络。输入文本字符串输出类型化结构multivariant 文本 ──parseMultivariantPlaylist──→ Presentation无 duration/segments media playlist 文本 ──parseMediaPlaylist──→ 补上 segments/duration/initialization两级解析的分工parse-media-playlist.ts:181-188的 spread 合并multivariant 产出PartiallyResolved*Track知道 URL、带宽、分辨率不知道分段各 track 的 URL 再 fetch 后交给 media playlist 解析器补全。parse-attributes.ts属性字符串解析187 行HLS 标签的属性长这样BANDWIDTH412000,RESOLUTION1920x1080,CODECSavc1.64001f,mp4a.40.2。核心正则L9/([A-Z0-9-])(?:([^]*)|([^,]*))/g值优先匹配双引号内整段——因为CODECSavc1.64001f,mp4a.40.2里的逗号是值的一部分不是分隔符。不先处理引号CODECS 会被逗号劈开。几个类型化的解析函数parseResolutionL25-33/^(\d)x(\d)$/。parseFrameRateL38-60容差匹配 NTSC 分数帧率——23.976±0.01 →24000/1001、29.97 →30000/1001、59.94 →60000/1001。NTSC 帧率是分数直接 parseFloat 会丢精度。parseCodecsL73-87按逗号拆分后按前缀分类。视频前缀avc1./hvc1./hev1.音频前缀mp4a./ac-3/ec-3/ac-4/opus/flac/...大小写不敏感fLaC靠 lower 匹配。L62-67 注释说明了动机识别不了的 codec 解析为空能力探测将无法裁剪它——宁可保守。parseExtInfDurationL92-96split(,)[0]剥掉可选标题#EXTINF:6.006,标题。parseByteRangeL103-121/^(\d)(?:(\d))?$/——有显式 offset 用之无 offset 用previousEnd续接返回闭区间{start, end: start length - 1}。getBoolL160-162严格 YES——HLS 布尔值只有 YES 算真。matchTagL182-186做#TAG:前缀匹配命中就对剩余部分建 AttributeList。parse-multivariant.tsmaster playlist395 行行扫描L72-151按行切分L33 的split(/\r?\n/)跳过空行和#EXTM3U/#EXT-X-VERSION等杂项标签。EXT-X-MEDIAL89-128处理音频/字幕 rendition 声明TYPE/GROUP-ID/NAME三者必须存在L92-94。有个细节我很欣赏——CHANNELS的解析L108HLS 里它是带引号字符串如6或16/JOC空间音频getInt只取前导整数L105-107 注释。EXT-X-STREAM-INFL130-151用两行式结构STREAM-INF 标签在上一行URI 在下一行。所以 L133-139 先把属性存进pendingStreamInfo不立即产出L144-150 遇到非#行且有待定信息时才resolveUrl合成完整 StreamInfo。这是 HLS spec 的quirk解析器必须处理。跨音频组的去重L183-236——本文件最关键的算法我读这段时先被背景注释L184-189教育了HLS 中同一视频 rendition 会按它可配对的每个音频组重复出现在多个 STREAM-INF 里笛卡尔积URI 相同。比如 3 个画质 × 2 个音频组 6 行 STREAM-INF但实际只有 3 个视频 rendition。解法L190-236consttracksByUrlnewMapstring,PartiallyResolvedVideoTrack();// L190 — keyURI 折叠// 同 URI 重复出现时把新的 audioGroupId 追加进 existing.audioGroupIdsL193-195但有个陷阱STREAM-INF 的 BANDWIDTH 是视频音频之和跨组重复项只在配对音频上不同。L197-202 的处理保留最小值作为「最接近纯视频带宽」的代理ABR 按它排序。而冗余流不同 CDN 的不同 URI不会被误合并——key 是 URIURI 不同就是不同 track。其余产出纯音频流L238-256mimeTypeaudio/mp4sampleRate 48000 / channels 2占位默认L251-252等 media playlist 修正。EXT-X-MEDIA 音频 rendition → trackL258-300从引用该 groupId 的 stream 的 CODECS 里「偷」出音频 codecL261-270——multivariant 不直接给 demuxed 音频的 codec这是 HLS 规范的空隙只能这么补。文本 trackL305-334对齐 hls.js 的行为——仅当DEFAULTYES且AUTOSELECTYES同时成立才置default: trueL322-325。最终 PresentationL387-394duration有意缺省L392 注释至少 fetchparse 一个 media playlist 之前不可知。parse-media-playlist.ts分段列表189 行状态机式行扫描L78-158状态变量L78-86initSegmentUrl/initSegmentByteRangeEXT-X-MAP、currentDurationEXTINF 暂存、currentByteRange、currentTime时间轴累加器、previousByteRangeEndBYTERANGE 无偏移时续接。关键标签处理EXT-X-MAPL106-117init segment 的 URI 可选 BYTERANGE偏移从 0 续接L111-114。EXTINFL120-123暂存时长。EXT-X-BYTERANGEL126-129parseByteRange(trimmed.slice(17), previousByteRangeEnd)——无显式 offset 时从上一段结束处续接。Segment URIL136-157非#且currentDuration 0时构建 Segmentid: segment-${index}、url、duration、startTime: currentTime然后currentTime currentDuration推进时间轴。三个值得注意的「不处理」#EXT-X-TARGETDURATION被显式忽略L98——总时长由 EXTINF 累加得出L160 的totalDuration currentTime不用 targetDuration × n。#EXT-X-ENDLIST只是 continueL131-133——解析器对 VOD/live 不做区分live 判定在别处streamType feature21 篇。容器嗅探L170-177fMP4 必有 EXT-X-MAP所以「无 map 识别到的扩展名」即非 fMP4——.ts→video/mp2t、.aac→audio/aacL23-26。这些 MIME 标记为当前不可播放交给能力探测裁剪。设计观察解析器的「无知」读完三个解析器我最深的印象是它们的克制——不知道的就不填duration 留空、不该管的就不管ENDLIST、live 判定、识别不了的保守处理codec 解析为空。解析器只做「忠实转译文本 → 类型」一切策略判断能不能播、是 live 吗都在下游。这让它们成为理想的纯函数给文本出结构Vitest 直接表驱动测试media/ 目录下 27 个测试文件大部分是解析器测试。小结引号优先的属性正则——CODECS 的逗号是值的一部分。两行式 STREAM-INF——pending 暂存URI 行才产出。URI 折叠去重 最小带宽代理——解 HLS 笛卡尔积坑。从 stream CODECS 偷音频 codec——补规范空隙。DEFAULTAUTOSELECT 双条件——对齐 hls.js 行为。targetDuration 显式忽略——时长 EXTINF 累加。容器嗅探——无 MAP 扩展名 → 非 fMP4 MIME。下一篇讲 ABR——带宽估计的双 EWMA 和质量选择的滞回算法。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑