HDR 片段与索引管理:CMAF/LL-HLS/DASH 的跨平台兼容
关键词:HDR、PQ、HLG、CMAF、LL-HLS、Low-Latency DASH、sidx、SegmentTimeline、#EXT-X-PART、MSE、ExoPlayer、AVPlayer、BT.2020、hvcC、nclx、emsg/ID3、独立片段
摘要:
面向移动与大屏的 HDR 分发,分段与索引既决定延迟与快进精度,也直接影响跨平台播放器对 PQ/HLG、BT.2020 等色彩信令的正确识别。本文以 CMAF 为核心,梳理 LL-HLS / Low-Latency DASH 的分片粒度(segment/part)、索引结构(sidx
、SegmentTimeline
、#EXT-X-MAP
等)与时间对齐(PTS/墙钟),总结 ExoPlayer / AVPlayer / Web(MSE) 在 HDR 清单与容器信令上的差异和“坑位”,并给出一套工程化的命名规范、独立片段策略、索引回填与降级路径,确保同一流在多端保持可播、可跳、可同步。
目录
-
目标与约束
HDR 分段的三重目标:低时延、精确 Seek、信令一致;约束:10-bit、BT.2020、PQ/HLG 单一映射。 -
分段粒度与时间轴
Segment(1–2s)与 Part(0.2–0.5s)的权衡;GOP 对齐、tfdt/trun
时间戳、PROGRAM-DATE-TIME
/UTCTiming 同步。 -
索引结构与清单要点
MP4/CMAF 的sidx
与顶层/子sidx
;DASH 的SegmentTemplate/Timeline
;HLS 的#EXT-X-MAP
、#EXT-X-PART
、#EXT-X-PRELOAD-HINT
与独立片段。 -
HDR 信令在容器/清单中的一致性
码流hvcC/vpcC
、容器colr(nclx)
、清单属性(PQ/HLG、BT.2020、2020nc)一致化;避免双重映射。 -
跨平台播放器差异与兼容策略
ExoPlayer(Android)、AVPlayer(iOS/tvOS)、Safari/Chrome(MSE)在低延迟、索引回填与 HDR 识别上的行为差异与兜底。 -
Seek/Trickplay 与缩略图轨
I-frame playlist / I-frame track、sidx
索引加速、缩略图雪碧图与字节范围;帧级 Seek 与容错。 -
在线稳健性:断点、插播与时钟漂移
EXT-X-DISCONTINUITY
/DASH Period 处理、emsg/ID3
标注、CDN 边缘缓存与时钟漂移校正、索引回补策略。 -
发布清单与回归门限
分段/索引命名规范、独立片段开关、清单与容器一致性检查、快进精度与起播时延门限、降级与回滚流程。
1. 目标与约束(HDR 分段/索引的“三角形”)
三重目标
- 低时延起播/切片:CMAF + LL-HLS/LL-DASH 下把 Camera→Glass 压到 1–1.3 s,同时保留亚秒级 part 推送。
- 精确 Seek/Trickplay:
sidx / SegmentTimeline / I-frame
三级索引,确保毫秒级时间轴与关键帧对齐。 - 信令一致与单次映射:码流(
hvcC/vpcC
)=容器(colr(nclx)
)=清单(PQ/HLG, BT.2020, 2020nc)一致,玩家端只做一次 EOTF。
硬性约束(工程口径)
维度 | 要求 | 说明 |
---|---|---|
位深/采样 | 10-bit, 分发 4:2:0 | 贡献链可 4:2:2 |
色彩 | primaries=BT.2020 ,matrix=BT.2020nc ,transfer=PQ/HLG |
统一到 nclx/清单 |
分片 | segment=1–2 s, part=0.2–0.5 s | part 与 GOP 严格对齐 |
GOP | keyint = segment × fps ,open-gop=0 |
边界 I/IDR |
索引 | CMAF sidx (顶/子)、DASH SegmentTimeline 、HLS #EXT-X-PART |
三级一致 |
时钟 | tfdt / PTS 单调;清单含 UTC/PROGRAM-DATE-TIME |
多端同步 |
起播/Seek | 起播 ≤ 1.5 s;Seek 到画面 ≤ 500 ms | 1080p60 参考 |
兼容 | ExoPlayer / AVPlayer / MSE | HLG/PQ 正确识别 |
端到端结构(索引落点示意)
flowchart LR
ENC[编码器 HEVC/AV1 10-bit] -->|GOP 对齐| MOOF[moof/traf/trun (CMAF chunk)]
INIT[init.mp4\nmoov+hvcC+colr(nclx)+sidx] -.首播/解码配置.-> PLAY[播放器]
MOOF --> CMAF[CMAF segment (1–2s): 若干 part (0.2–0.5s)]
CMAF --> HLS[#EXTM3U\n#EXT-X-MAP\n#EXT-X-PART\n#EXT-X-PRELOAD-HINT]
CMAF --> DASH[MPD\nSegmentTemplate/Timeline\nUTCTiming]
INIT --> HLS
INIT --> DASH
HLS --> PLAY
DASH --> PLAY
成功标准(可量化)
- 色彩信令对齐:码流/容器/清单三致;误配=0。
- 时间轴正确性:
tfdt
单调;GOP 与 segment/part 对齐偏差 ≤ 1 帧。 - 交互:首帧 ≤ 1.5 s,向前/后 10 s Seek 的中位回显 ≤ 500 ms。
- 稳定性:
Flicker-L ≤ 0.02
;分片/part 丢失可在 ≤1 个 segment 内恢复。
2. 分段粒度与时间轴(Segment/Part/GOP/PTS 的四件事)
2.1 粒度选择与 GOP 关系
- Segment(1–2 s):ABR 切层、缓存与索引效率的折中;必须以 IDR 起始。
- Part(0.2–0.5 s):低延迟核心;part 边界应落在参考链断点(I 或至少不跨 GOP 参考)。
- GOP:
keyint = segment × fps
(例如 60 fps → keyint=60@1 s);禁 Open-GOP 以避免跨片参考。
gantt
title GOP/Segment/Part 对齐(60fps 示例)
dateFormat x
section GOP
GOP#1 :a1, 0, 1000
GOP#2 :a2, 1000, 1000
section Segment
seg_0(1s) :s1, 0, 1000
seg_1(1s) :s2, 1000, 1000
section Part(0.25s)
p0 :p1, 0, 250
p1 :p2, 250, 250
p2 :p3, 500, 250
p3 :p4, 750, 250
p4 :p5, 1000, 250
p5 :p6, 1250, 250
p6 :p7, 1500, 250
p7 :p8, 1750, 250
经验法则:
part_duration × 3 ≈ 播放器 hold-back
;例如 part=0.33 s → hold-back≈1.0 s。
2.2 时间戳与 tfdt/trun
(CMAF 内部)
tfdt
(baseMediaDecodeTime):以 timescale 计数的段解码起点;必须单调递增,跨 segment/part 连续。trun
:每帧的 sample duration/offset;确保 PTS/DTS 单调 与 sample 边界对齐。- Timescale:常用 90000;过低会导致Seek 量化误差,过高则索引膨胀。
快速自检(MP4Box/gpac)
MP4Box -info seg_0001.m4s | grep -E "tfdt|trun|timescale"
2.3 HLS(LL-HLS)清单要点
#EXT-X-MAP
:初始化段,承载moov+hvcC+colr(nclx)
。#EXT-X-PART
:part 列表;PART-TARGET
=part 时长;PRELOAD-HINT
预取下一 part。- 独立片段:
#EXT-X-INDEPENDENT-SEGMENTS
;segment 起始必须可独立解码。
示例(0.333 s part,2 s segment)
#EXTM3U
#EXT-X-VERSION:9
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-PART-INF:PART-TARGET=0.3333
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=1.0
#EXT-X-MAP:URI="init_1080p.mp4"
#EXTINF:2.000,
chunk_1080p_1024.m4s
#EXT-X-PART:DURATION=0.3333,URI="chunk_1080p_1025.m4s?part=0"
#EXT-X-PART:DURATION=0.3333,URI="chunk_1080p_1025.m4s?part=1"
#EXT-X-PART:DURATION=0.3333,URI="chunk_1080p_1025.m4s?part=2"
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="chunk_1080p_1025.m4s?part=3"
色彩信令(必须显式)
- 在打包端确保
init.mp4
的colr(nclx)
:primaries=9(bt2020) / transfer=16(PQ)或18(HLG) / matrix=9(bt2020nc)
。 - 若多档位(ABR),所有档位一致标记,避免切层色偏/跳亮。
2.4 DASH(LL-DASH)清单要点
SegmentTemplate
+SegmentTimeline
:用t/d/r
精确描述每个段的时间,支持不等长片段。UTCTiming
:与墙钟同步,便于多流/多设备对时。- LL 模式:packager 侧启用 chunked CMAF 输出,播放器边拉边播。
示例(片段节选)
<MPD type="dynamic" minimumUpdatePeriod="PT1S" availabilityStartTime="2025-09-02T09:00:00Z">
<UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-iso:2014" value="https://time.example.com/utc"/>
<Period start="PT0S">
<AdaptationSet mimeType="video/mp4" codecs="hvc1.2.4.L153.B0"
colorPrimaries="9" transferCharacteristics="18" matrixCoefficients="9">
<Representation id="v1080p" bandwidth="9000000" width="1920" height="1080" frameRate="60">
<SegmentTemplate timescale="90000" initialization="init_$RepresentationID$.mp4"
media="chunk_$RepresentationID$_$Number$.m4s" startNumber="1024">
<SegmentTimeline>
<S t="5400000" d="180000" r="9"/> <!-- 2s segments with parts inside -->
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
</MPD>
2.5 推荐打包参数(可直接使用)
ffmpeg → LL-DASH(HEVC/HDR)
ffmpeg -re -i input_hlg_bt2020_10bit.mov \
-c:v libx265 -pix_fmt yuv420p10le -preset veryfast -tune zerolatency \
-x265-params "keyint=60:min-keyint=60:open-gop=0:bframes=0:rc-lookahead=0:
vbv-maxrate=9000:vbv-bufsize=10800:hrd=1:sao=1:repeat-headers=1" \
-color_primaries bt2020 -colorspace bt2020nc -color_trc arib-std-b67 \
-f dash -streaming 1 -ldash 1 -use_timeline 1 -use_template 1 \
-seg_duration 2 -frag_type every_frame \
-init_seg_name 'init_$RepresentationID$.mp4' \
-media_seg_name 'chunk_$RepresentationID$_$Number$.m4s' out.mpd
gpac(MP4Box)→ CMAF HLS/LL-HLS
MP4Box -dash 2000 -frag 333 -rap -segment-name chunk_$RepresentationID$_$Number$ \
-profile dashavc264:live -segment-ext m4s -url-template \
-mpd-title live_hlg -subdur 0 input_hlg_bt2020_10bit.mp4
# 备注:-dash 2000=2s segment;-frag 333=0.333s part;-rap 以 IDR 对齐
2.6 常见坑位与快速修复
现象 | 根因 | 修复 |
---|---|---|
切层闪烁/色偏 | 不同档位 nclx/hvcC 不一致 |
统一 primaries/transfer/matrix |
起播慢 | part 过长或未启用 chunked 传输 |
part=0.2–0.5 s;开启 chunked |
Seek 停滞 | sidx 缺失/错误、tfdt 不单调 |
生成顶/子 sidx ;校验 tfdt |
解码失败 | segment 不是独立片段、Open-GOP | open-gop=0 ,INDEPENDENT-SEGMENTS |
时间不同步 | 无 UTCTiming /PROGRAM-DATE-TIME |
补齐对时源并对齐 PTS |
3. 索引结构与清单要点(CMAF / LL-HLS / DASH)
目标:用一致的索引层级(sidx
/ SegmentTimeline
/ #EXT-X-PART
)把低延迟、精确 Seek与多端可播统一起来。
3.1 CMAF 内部索引:sidx
、tfdt
、trun
-
两级 sidx(推荐)
- 顶层 sidx(可放在
init.mp4
或首段头部):索引 segment 级别(1–2 s)。 - 子 sidx(每个 segment 内开头):索引 subsegment/part(0.2–0.5 s)。
reference_type=0
指向媒体块;reference_type=1
可指向下游 sidx(子索引)。
- 顶层 sidx(可放在
-
时间轴
tfdt.baseMediaDecodeTime
必须单调递增;trun.sample_duration
/composition_time_offset
保证 PTS/DTS 单调。- timescale:推荐 90000(毫秒级 Seek 精度/跨端一致)。
-
独立片段
- IDR 起段(
open-gop=0
),切片/切层可在 segment 边界直接起播。
- IDR 起段(
快速校验(gpac/MP4Box)
MP4Box -info seg_0001.m4s | egrep "sidx|tfdt|trun|timescale"
MP4Box -diso init.mp4 | egrep "hvcC|colr|nclx|sidx"
3.2 HLS(含 LL-HLS)索引与清单
-
Master Playlist(编解码/色彩/范围)
CODECS="hvc1…"
(HEVC)或av01.…
(AV1);VIDEO-RANGE=PQ|HLG|SDR
;FRAME-RATE
/RESOLUTION
明确。- 推荐
hvc1
(Apple 兼容性更好;参数集在hvcC
),不要混用hev1
。
Master 例:1080p60 HLG + 720p60 SDR 降级
#EXTM3U
#EXT-X-VERSION:9
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:BANDWIDTH=9000000,AVERAGE-BANDWIDTH=8000000,CODECS="hvc1.2.4.L153.B0",
RESOLUTION=1920x1080,FRAME-RATE=60.000,VIDEO-RANGE=HLG
1080p_hlg.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=4500000,AVERAGE-BANDWIDTH=4000000,CODECS="avc1.4d4029",
RESOLUTION=1280x720,FRAME-RATE=60.000,VIDEO-RANGE=SDR
720p_sdr.m3u8
-
Media Playlist(LL-HLS 部分)
#EXT-X-MAP
:init.mp4
(含moov+hvcC+colr(nclx)
)。#EXT-X-PART-INF:PART-TARGET=0.3333
+#EXT-X-PART
序列;#EXT-X-PRELOAD-HINT
预取下一 part。#EXT-X-SERVER-CONTROL:PART-HOLD-BACK=3×part
(常用 1.0s 左右),CAN-BLOCK-RELOAD=YES
。
Media 例:2 s segment + 0.333 s part
#EXTM3U
#EXT-X-VERSION:9
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-PART-INF:PART-TARGET=0.3333
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=1.0
#EXT-X-MAP:URI="init_1080p.mp4"
#EXTINF:2.000,
chunk_1080p_1024.m4s
#EXT-X-PART:DURATION=0.3333,URI="chunk_1080p_1025.m4s?part=0"
#EXT-X-PART:DURATION=0.3333,URI="chunk_1080p_1025.m4s?part=1"
#EXT-X-PART:DURATION=0.3333,URI="chunk_1080p_1025.m4s?part=2"
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="chunk_1080p_1025.m4s?part=3"
3.3 DASH(含 LL-DASH)索引与清单
- SegmentTemplate + SegmentTimeline:用
t/d/r
精确描述时间,支持不等长段;timescale=90000
。 - UTCTiming:与墙钟对齐,便于跨流同步/对时。
- 色彩属性:在 AdaptationSet/Representation 上标注
colorPrimaries/transferCharacteristics/matrixCoefficients
。
MPD 片段(HLG,1080p60)
<MPD type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011"
minimumUpdatePeriod="PT1S" availabilityStartTime="