ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Shaka Player 的 DASH Preselection 完整指南:从 NGA 多体验音轨到 AC-4 ALPS 集成实战

Shaka Player 的 DASH Preselection 完整指南:从 NGA 多体验音轨到 AC-4 ALPS 集成实战 Shaka Player 的 DASH Preselection 完整指南从 NGA 多体验音轨到 AC-4 ALPS 集成实战【免费下载链接】shaka-playerJavaScript player library / DASH HLS client / MSE-EME player项目地址: https://gitcode.com/GitHub_Trending/sh/shaka-player本指南以仓库文档 docs/tutorials/preselection.md 为骨架结合 lib/dash/dash_parser.js 等源码实现展开。导读DASH PreselectionISO/IEC 23009-1 第 5.3.11 条款是为下一代音频Next Generation AudioNGA编解码器设计的一种预定义用户体验机制一条媒体流可以同时携带多套体验例如完整主混音、对话增强混音、口述影像混音它们全部复用在相同的媒体分片里。本文以 Shaka Player 的实际实现为主线讲解 Preselection 在 MPD 中的两种信号形式、解析器如何把它们物化为普通音轨、如何用现有音轨 API 完成选择以及如何通过mediaSource.modifyPreselectionSegmentCallback配合 Dolby ALPS 重写分片让平台解码器选中正确的体验。读完本文你将能独立为 AC-4 / MPEG-H 流编写一份可运行的 Preselection 集成方案。Preselection 是什么为 NGA 而生的一鱼多吃音轨机制传统 DASH 中一个音频AdaptationSet对应一种语言、一条码率的音轨客户端按需切换。NGA 编解码器Dolby AC-4、MPEG-H 3D Audio打破了这一假设单个编码流即可承载多个同时呈现的体验例如完整主混音main mix对话增强混音dialogue-enhanced mix口述影像混音audio-description mix。这些体验在码流层复用elementary-stream 级别的多路复用共用同一组分片。为了让 DASH 客户端能选中其中某一种体验ISO/IEC 23009-1 第 5.3.11 条款定义了Preselection它在 MPD 中预先描述一组组件及其属性语言、标签、角色、声道数、编解码器标识等客户端无需理解码流内部结构即可按体验选择。Shaka Player 对 Preselection 的支持范围是组件解析到单一音频 AdaptationSet的 Preselection这是 AC-4 与 MPEG-H fat stream 的常见形态。实现上的关键设计是——每个 Preselection 会被物化成一条普通的音频轨因此不需要新增任何 API现有的音轨选择 API 与 UI 面板无需改动即可工作对上层完全透明应用代码看到的就是带不同label、language的若干音频轨。在 MPD 中信号 Preselection两种形式与完整示例规格定义了两种信号方式Shaka Player 的解析器processPreselections_见 lib/dash/dash_parser.js对两者都支持。形式一Period 级 Preselection 元素推荐、支持属性覆盖在Period下直接声明Preselection元素通过preselectionComponents引用 AdaptationSetPeriod id1 AdaptationSet id1 mimeTypevideo/mp4 ... /AdaptationSet !-- An AC-4 stream carrying several presentations. The EssentialProperty descriptor marks it as only consumable through its Preselections. -- AdaptationSet id2 mimeTypeaudio/mp4 codecsac-4.02.01.00 EssentialProperty schemeIdUriurn:mpeg:dash:preselection:2016/ Representation ida bandwidth256000 ... /Representation /AdaptationSet Preselection id10 tag0 langen preselectionComponents2 codecsac-4.02.01.01 LabelEnglish dialogue/Label Role schemeIdUriurn:mpeg:dash:role:2011 valuemain/ /Preselection Preselection id20 tag1 langen preselectionComponents2 codecsac-4.02.01.02 LabelEnglish dialogue enhanced/Label Role schemeIdUriurn:mpeg:dash:role:2011 valuealternate/ /Preselection /Period每个 Preselection重新描述该体验它的lang、codecs、AudioChannelConfiguration、Label、Role和Accessibility会替换对应 AdaptationSet 上的取值详见后文applyPreselectionToStream_的源码解析。这是规格第 5.3.11.3 条款规定的Preselection 覆盖 AdaptationSet语义。形式二描述符descriptor形式除了元素形式Preselection 也可以通过AdaptationSet上的EssentialProperty/SupplementalProperty描述符来信号schemeIdUri 均为urn:mpeg:dash:preselection:2016。解析器对描述符value的格式解析见 lib/dash/dash_parser.jsvalue的格式是tag,id listPreselection Tag 逗号 空白分隔的 AdaptationSet / ContentComponent id 列表第一个 id 是 Main AdaptationSet无value时描述符仅标记该 AdaptationSet 属于某个在别处定义的 Preselection解析时以最后一个逗号作为 Tag 与 id 列表的分隔符id 列表只含数字和空白因此即使 Tag 本身包含逗号也能正确拆分。两种描述符的语义区别决定音轨是否隐藏描述符语义Shaka Player 行为EssentialPropertyAdaptationSet 只能通过其 Preselection 消费原始音轨隐藏仅暴露各 Preselection 对应的音轨SupplementalPropertyAdaptationSet 属于某 Preselection但也可单独消费Preselection 音轨与原始音轨并存解析器会同时收集元素定义与描述符定义lib/dash/dash_parser.js元素形式保留 XML 节点以便后续应用覆盖属性描述符形式不携带覆盖直接复用 AdaptationSet 自身描述。解析器如何把 Preselection 变成音轨源码级拆解processPreselections_是核心入口lib/dash/dash_parser.js执行流程如下第一步归一化定义并校验。遍历所有 Preselection 定义元素 描述符逐条校验引用的 id 必须都能匹配到 AdaptationSet引用 ContentComponent 视为不支持见 lib/dash/dash_parser.js一个 Preselection 只能引用一个AdaptationSet多 AdaptationSet 的 Preselection 尚不支持见 lib/dash/dash_parser.js该 AdaptationSet 必须是音频且非 trick mode 集见 lib/dash/dash_parser.js。第二步为元素形式复制流对象。通过在 Preselection 专属 context name 下重新解析 AdaptationSetcontext name 为preselection_ definition.id生成一组独立的流副本保证副本在 manifest 更新期间具有稳定的对象身份与依赖流使用同一模式见 lib/dash/dash_parser.js。第三步应用 Preselection 覆盖。applyPreselectionToStream_lib/dash/dash_parser.js为每条流副本设置stream.preselection {id, tag}其中tag直接取自tag属性缺失则为nulloriginalId追加_preselection_id后缀groupId追加同名后缀——注释明确指出这是为了把副本从原始流的音频组中隔离出去使 ABR 永远不会在同一 AdaptationSet 的不同 Preselection 之间跳动见 lib/dash/dash_parser.js覆盖language经LanguageUtils.normalize规范化、codecs并重建fullMimeTypes、label、channelsCount来自子元素AudioChannelConfiguration、roles/primary来自Role元素、accessibilityPurpose来自urn:tva:metadata:cs:AudioPurposeCS:2007的Accessibility。由于 manifest 更新时流对象可能复用所有这些变更都被设计为幂等操作见 lib/dash/dash_parser.js 的注释。第四步组装与过滤。依据描述符的 essential/supplemental 语义决定暴露哪些流lib/dash/dash_parser.js有副本且 essential用 Preselection 副本替换原始流有副本且 supplemental副本追加到原始流之后无副本但 essential 且未被任何受支持 Preselection 引用整个 AdaptationSet 被过滤掉并输出 warning。上述行为在 test/dash/dash_parser_manifest_unit.js 的Preselection测试套件中均有覆盖creates a track per Preselection element断言副本流的originalId为a_preselection_10、preselection为{id: 10, tag: 1}ignores sets only consumable through unsupported Preselections验证了多组件 Preselection 被忽略时 essential 集被整体丢弃。仓库解析器将urn:mpeg:dash:preselection:2016列入受支持的 EssentialProperty scheme 白名单lib/dash/dash_parser.js。选择 Preselection复用现有音轨 API无需新接口Preselection 生成的是普通音频轨因此选择逻辑完全走既有 APIconst tracks player.getAudioTracks(); // e.g. [{language: en, label: English dialogue, ...}, // {language: en, label: English dialogue enhanced, ...}] player.selectAudioTrack(tracks[1]);selectAudioTrack的实现lib/player.js会把所选音轨的codecs、language、roles[0]、label、channelsCount、spatialAudio写入当前自适应集判据的配置然后调用chooseVariantAndSwitch_(/* clearBuffer */ true, ...)。clearBuffer true正是文档所述切换后清空音频缓冲并重新拉取分片行为的来源——这保证新选择的体验立即生效也让下方将要介绍的重写回调在每次选择变更后都会对新分片重新执行天然与 UI 保持同步无需额外的协调逻辑。重写分片让解码器选中目标体验modifyPreselectionSegmentCallback为什么需要重写选择某条 Preselection 音轨并不改变下载的字节所有体验都复用在同一组分片里最终是媒体引擎播放器侧的解码链决定解码出哪一种体验。MSE 没有任何 API 可以把 Preselection 的 tag 直接传给平台解码器因此分片通常需要被重写使解码器选中正确的体验。这一处理是编解码器相关的AC-4 与 MPEG-H 各自有独立的改写逻辑所以 Shaka Player 把它委托给应用层通过一个配置回调实现。配置入口与默认行为player.configure(mediaSource.modifyPreselectionSegmentCallback, (preselectionSegmentInfo) { // Rewrite preselectionSegmentInfo.data here as needed. return preselectionSegmentInfo; });该回调在 lib/util/player_configuration.js 中注册默认实现是原样返回传入对象return preselectionSegmentInfo;因此未配置时不产生任何行为差异。调用时机与回调对象回调在任何属于 Preselection 的流的分片被追加进 SourceBuffer 之前被调用实际调用点位于 lib/media/media_source_engine.js 的appendBuffer_内部当stream.preselection存在时构造 info 对象、调用回调、用回调返回的data替换待追加数据。回调接收一个shaka.extern.PreselectionSegmentInfo对象类型定义见 externs/shaka/player.js字段如下字段类型描述dataBufferSource即将被追加的分片数据preselection{id: string, tag: ?string}该流所属的 Preselectionstreamshaka.extern.Stream正在被追加的流contentTypestringaudio或videoisInitSegmentboolean为 true 表示是初始化分片实现中以reference null判定见 lib/media/media_source_engine.js需要注意preselection.tag的类型是字符串?string因为它直接来自 MPD 的tag属性。回调返回可能被修改后的info 对象默认不修改。由于切换音轨时音频缓冲会被清空新选中 Preselection 的分片会再次流过这个回调因此回调始终面对的是当前活跃的 Preselection不需要与 UI 做额外同步。实战AC-4 流 Dolby ALPS 的完整集成对于 Dolby AC-4Dolby 提供了开源的 alps-web 库用于重写 ISOBMFF 分片中的 AC-4 目录table of contents使解码器选中给定的 presentation。安装npm install --save dolbylaboratories/alps完整集成代码含类型转换显式标注import {Alps} from dolbylaboratories/alps; const alps new Alps(); player.configure(mediaSource.modifyPreselectionSegmentCallback, (preselectionSegmentInfo) { // ALPS only understands AC-4; ignore other Preselection streams. const codecs preselectionSegmentInfo.stream.codecs || ; if (!codecs.toLowerCase().startsWith(ac-4)) { return preselectionSegmentInfo; } // Type note: Shaka Player exposes the Preselection tag as a string // (?string), because it comes from an MPD attribute. ALPS identifies // AC-4 presentations by number, so convert it. -1 selects the default // presentation if the tag is missing or not numeric. let presentationId parseInt(preselectionSegmentInfo.preselection.tag, 10); if (Number.isNaN(presentationId)) { presentationId -1; } // Type note: Alps.processIsoBmffSegment() takes an ArrayBuffer and // modifies it in place (its return value is only metadata), while // preselectionSegmentInfo.data is a BufferSource — usually a // Uint8Array view. toArrayBuffer() unwraps the view when it spans the // whole underlying buffer and copies it otherwise, so always append // the ArrayBuffer that ALPS actually processed. const buffer shaka.util.BufferUtils.toArrayBuffer( preselectionSegmentInfo.data); // ALPS detects init vs. media segments on its own, so every segment // can be processed the same way. Passing the presentation ID on each // call keeps the integration stateless (it takes precedence over // Alps.setActivePresentationId()). alps.processIsoBmffSegment(buffer, /* streamId */ null, presentationId); preselectionSegmentInfo.data buffer; return preselectionSegmentInfo; });代码中两处关键的类型转换是集成最容易出错的地方此处特意显式标出Shaka PlayerALPS转换preselection.tag?stringpresentationIdnumberparseInt(tag, 10)失败回退-1dataBufferSourcesegmentBufferArrayBuffershaka.util.BufferUtils.toArrayBuffer()回调是同步的processIsoBmffSegment()是同步的无需额外处理BufferUtils.toArrayBuffer是 Shaka Player 自带的工具方法被 lib/drm/fairplay.js、lib/metadata/id3_utils.js 等广泛使用当视图恰好完整覆盖底层 buffer 时直接解包否则复制因此 ALPS 实际处理的ArrayBuffer一定是被写入回调返回值的那个。MPD tag 与码流 presentation_id 的对应关系MPD 中每个 Preselection 的tag属性必须与 AC-4 码流中携带的presentation_id一致参见 ETSI TS 103 190-2——正是这个对应关系把用户选中的音轨与 ALPS 激活的 presentation 关联起来。若你想核对 MPD 信号与码流是否匹配可以监听 ALPS 在 init 分片中发现的 presentationsalps.setPresentationsChangedEventHandler((event) { // Presentation ids here are numbers, e.g. [{id: 0, ...}, {id: 1, ...}]. console.log(AC-4 presentations:, alps.getPresentations(event.streamId)); });多 Period 场景对于 AC-4 配置在 Period 之间发生变化的时长片内容可以通过processIsoBmffSegment()的streamId参数按 Period 分别跟踪并配合clearStream()清理单一配置下传null如上面的示例即可。注意事项与当前限制解码能力仍是硬前提播放依然要求平台支持该音频编解码器。大多数桌面浏览器无法解码 AC-4 或 MPEG-H在这些设备上Preselection 音轨会和其他不支持码率/变体一起被过滤掉。本功能主要面向内置 NGA 解码器的设备智能电视、机顶盒等。多 AdaptationSet 组件不支持组件跨多个 AdaptationSetpreselectionComponents含多个 id或引用 ContentComponent 的 Preselection 目前会被忽略仅标记为只能通过这些不支持 Preselection 消费的 AdaptationSet 也会一并被忽略测试ignores sets only consumable through unsupported Preselections验证了这一点见 test/dash/dash_parser_manifest_unit.js。离线存储完整保留 Preselection 信息下载时stream.preselection关联会被持久化lib/offline/storage.js恢复 manifest 时重新挂回流对象lib/offline/manifest_converter.js。因此离线播放时modifyPreselectionSegmentCallback同样会被调用集成代码无需区分在线/离线。仅音频 Preselection从 lib/dash/dash_parser.js 的校验可见非音频 AdaptationSet 上的 Preselection 会被拒绝stream.preselection默认值为null见 lib/util/periods.js、lib/util/stream_utils.js说明该字段对所有非 Preselection 流保持空值。小结Shaka Player 对 DASH Preselection 的实现遵循信号即音轨的设计哲学解析器把两种信号形式归一化为带preselection注解的普通音轨选择逻辑完全复用既有 API分片改写通过一个同步配置回调下放给应用。整个链路中需要你关心的只有两件事确保 MPD 的tag与码流中的 presentation id 一致以及按上文的类型转换规则正确接入你选定的 NGA 处理库如 Dolby ALPS。相关源码与测试可进一步查阅 lib/dash/dash_parser.js、lib/media/media_source_engine.js 与 test/dash/dash_parser_manifest_unit.js。【免费下载链接】shaka-playerJavaScript player library / DASH HLS client / MSE-EME player项目地址: https://gitcode.com/GitHub_Trending/sh/shaka-player创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表