Shaka Player 升级指南:从 v2.1 到 v2.4 的完整迁移手册
2026/9/16 21:14:12 网站建设 项目流程

Shaka Player 升级指南:从 v2.1 到 v2.4 的完整迁移手册

【免费下载链接】shaka-playerJavaScript player library / DASH & HLS client / MSE-EME player项目地址: https://gitcode.com/GitHub_Trending/sh/shaka-player

本篇指南以 Shaka Player 官方升级文档 docs/upgrades/upgrade-v2.1-to-v2.4.md 为主体,系统梳理从 v2.1 升级到 v2.4 过程中涉及的全部 API 变更、配置项迁移与新能力引入,并结合当前仓库的 lib 目录源码与 externs 声明文件进行源码级佐证。读完本文,你将掌握文本渲染、ABR 码率自适应、流失败重试、离线存储、网络请求与插件体系等模块在 v2.4 中的新写法,并能在不踩坑的前提下完成应用代码迁移。

一、v2.4 带来了什么

升级文档开篇即列举了 v2.1 到 v2.4 之间的核心改进,按主题可归纳为以下几类:

  • 文本与字幕:允许应用自绘文本轨道;支持 CEA 字幕(TS 内容);支持 TTML 与 VTT 的 region 布局;字幕在显示前不再被提前流式下载。
  • 码率自适应(ABR):默认 ABR 管理器更加可配置;vaiant 轨道上新增声道数与带宽信息;使用 NetworkInformation API 获取初始带宽估算。
  • 流式传输与网络:Fetch 优先于 XHR(可用时);网络请求变为可中止(abortable);直播可在距离直播边缘负偏移处开始播放。
  • 格式与清单:支持 HLS 直播流;支持开始时间不为 t=0 的 HLS VOD 流;MPEG-2 TS 内容可被转封装(transmux)为 MP4 以在所有浏览器播放;DASH 支持 Xlink。
  • Player 生命周期:构造Player时不再强制要求传入 video 元素,新增 attach() 与detach()方法管理 video 元素挂载。
  • 其他:离线内容支持"无持久化许可"(即无 license persistence)方案;EME 证书配置运行时类型检查更严格;示例应用(demo)升级为可离线使用的 PWA。

需要说明的是,本文聚焦 v2.4 相对 v2.1 的 API 变化。当前仓库的 lib/player.js 等实现已远超出 v2.4 的能力范围,但文档中描述的接口契约(如TrackChoiceAbrManager等)在 externs 中仍可找到一一对应的声明,可以作为迁移目标的权威依据。

二、新的shaka.text命名空间

在 v2.1 中,TextEngine隶属于shaka.media命名空间;从 v2.2 起,它被迁移到新的shaka.text命名空间。文本解析插件现在应通过shaka.text.TextEngine.registerParser注册。

当前仓库中 lib/text/text_engine.js 即为该迁移后的实现:

static registerParser(mimeType, plugin) { shaka.text.TextEngine.parserMap_.set(mimeType, plugin); }

同时它还提供了unregisterParser(mimeType)findParser(mimeType)两个配套静态方法(见 lib/text/text_engine.js)。TextEngine的构造函数签名为new TextEngine(displayer, manifestType),其中displayershaka.extern.TextDisplayer实例——这正是下一节自定义字幕显示的挂载点。

三、自定义字幕显示(Customizing subtitle display)

v2.1 允许应用接入自定义文本解析器,但字幕的最终显示完全由浏览器负责。v2.2 起 Shaka 将"显示"环节也开放给应用:默认情况下渲染工作由shaka.text.SimpleTextDisplayer类完成,应用可通过player.configure()指定自定义的文本显示工厂:

player.configure({ textDisplayFactory: customTextDisplayerClass });

自定义显示类需要实现shaka.extern.TextDisplayer接口(声明见 externs/shaka/player.js),核心职责包括append(cues)remove(startTime, endTime)destroy()等。从 lib/player.js 的默认配置可以看到,Player 在构造默认配置时便通过工厂函数懒加载 displayer——工厂接收 player 实例作为参数,应用也可以基于此实现"运行时根据场景选择 displayer"的逻辑。

在 lib/text/text_engine.js 中可以看到渲染链路:解析出的 cues 会先经过可选的modifyCueCallback修改(可用于样式或时间戳校正),再按 append window 过滤后交给displayer_.append(cuesToAppend)

四、文本解析器 API 变更(破坏性)

v2.4 对文本解析插件 API 做了不向后兼容的修改,所有应用自带的解析插件必须更新:

  1. 返回值:插件现在返回shaka.text.Cue对象数组,而非 v2.1 的VTTCue/TextTrackCue
  2. 入参parseMedia的 data 参数由ArrayBuffer改为Uint8Array
  3. 时间上下文timeContext.segmentStart变为可空(nullable)。当该信息不可用(例如 HLS 场景)时,插件会收到null

对照代码迁移示例:

// v2.1 MyTextParser.prototype.parseMedia = function(data, timeContext) { var cues = []; var parserState = new MyInternalParser(data); // ArrayBuffer while (parserState.more()) { cues.push(new VTTCue(...)); } return cues; }; // v2.4 MyTextParser.prototype.parseMedia = function(data, timeContext) { var cues = []; var parserState = new MyInternalParser(data); // Uint8Array while (parserState.more()) { cues.push(new shaka.text.Cue(...)); } return cues; };

在仓库中,externs/shaka/text.js 定义了shaka.extern.TextParser接口,parseMedia(data, timeContext, uri, images)返回!Array<!shaka.text.Cue>;externs/shaka/text.js 定义了TimeContext,包含periodStartsegmentStartsegmentEndvttOffsetisMpegTs五个字段。TextEngine.appendBuffer内部正是构造该time对象并传给解析器(见 lib/text/text_engine.js)。

shaka.text.Cue类包含与VTTCue相同的 cue 信息,并额外携带文本样式(样式相关字段与textDisplayFactory配合可实现完全自定义的渲染效果)。

注意:v2.4不提供该变更的向后兼容层,升级时必须同步更新全部文本解析插件。

五、ABR 管理器的设置与配置

5.1 配置入口变更

v2.1 中自定义 ABR 管理器通过abr.manager配置项注入,v2.4 改为顶层abrFactory

// v2.1 player.configure({ abr.manager: customAbrManager }); // v2.4 player.configure({ abrFactory: customAbrManager });

5.2 AbrManager 接口变更

v2.1 中,默认带宽估算与码率限制通过setDefaultEstimate()setRestrictions()两个独立方法设置;v2.4 统一收敛为configure()方法,接受一个shaka.extern.AbrConfiguration结构(声明位于 externs/shaka/player.js):

// v2.1: abrManager.setDefaultEstimate(defaultBandwidthEstimate); abrManager.setRestrictions(restrictions); // v2.4: abrManager.configure(abrConfigurations);

新方法更通用,除默认带宽与限制外,还允许配置带宽升/降级目标(bandwidthUpgradeTarget/bandwidthDowngradeTarget)。在默认实现 lib/abr/simple_abr_manager.js 中,configure(config)将配置缓存到this.config_并同步给内部的EwmaBandwidthEstimator

5.3 流选择 API:chooseStreams()chooseVariant()

v2.1 中 Player 通过chooseStreams()请求流选择,AbrManager 通过switch()回调把"主动建议的变更"回传,参数是 audio/video 流的映射表;v2.4 中chooseStreams()chooseVariant()取代,switch()回调直接接收一个 variant:

// v2.1: var map = abrManager.chooseStreams(['audio', 'video']); console.log(map['video'], map['audio']); MyAbrManager.prototype.makeDecision_ = function() { var video = this.computeBestVideo_(this.bandwidth_); var audio = this.computeBestAudio_(this.bandwidth_); var map = { 'audio': audio, 'video': video }; this.switch_(map); }; // v2.4: var variant = abrManager.chooseVariant(); console.log(variant, variant.video, variant.audio); MyAbrManager.prototype.makeDecision_ = function() { var variant = this.computeBestVariant_(this.bandwidth_); this.switch_(variant); };

当前仓库的shaka.extern.AbrManager接口(externs/shaka/abr_manager.js)完整反映了这一演进:setVariants(variants, isLowLatency)chooseVariant(preferFastSwitching)enable()/disable()configure(config)等。switchCallback的语义也已明确——第一个参数是要切换到的 variant,第二、三个可选参数控制是否清空缓冲(clearBufferSwitch)以及清缓冲时保留的安全余量秒数(safeMarginSwitch),后者可用于实现无卡顿的快速切换。

v2.1 的旧接口在 v2.2 被标记废弃、v2.3 被移除,所有自定义 AbrManager 插件必须更新到 v2.4 接口。

六、切换历史(Switch History)的变化

v2.1 中shakaExtern.Stats.switchHistory使用shakaExtern.StreamChoice结构,type字段为 'audio' / 'video' / 'text'。v2.2 起改名为shakaExtern.TrackChoice,语义从"流"细化到"轨道":

// v2.1: shakaExtern.StreamChoice; // id: 流 id;type: 'audio'/'video'/'text' // v2.4: shakaExtern.TrackChoice; // id: 轨道 id;type: 'variant'/'text';新增 bandwidth

仓库 externs/shaka/player.js 中的shaka.extern.TrackChoice定义与升级文档完全一致:{ timestamp, id, type: 'variant'|'text', fromAdaptation, bandwidth: ?number },其中fromAdaptation表示该切换是 ABR 自适应(true)还是应用主动调用选择接口(false),bandwidth对文本轨为null

lib/util/switch_history.js 提供了SwitchHistory实现:updateCurrentVariant(newVariant, fromAdaptation)updateCurrentText(newText, fromAdaptation)会去重记录冗余切换,getCopy()返回历史副本;文本轨的 bandwidth 固定记录为null(lib/util/switch_history.js),与 typedef 约定一致。开发者通过player.getStats().switchHistory即可拿到该数组用于分析码率切换行为。

七、流失败后的自定义重试逻辑

这是 v2.2 引入、v2.4 完整成型的核心能力。v2.0 时代,网络错误且重试耗尽后流式传输会无限继续重试请求,唯一的终止方式是unload()destroy();v2.1.3 增加了streaming.infiniteRetriesForLiveStreams配置来单独控制直播重试;v2.2 则替换为更灵活的streaming.failureCallback回调机制,覆盖所有流类型:

// v2.1 player.configure({ streaming: { infiniteRetriesForLiveStreams: true // 默认值 } }); // v2.4 player.configure({ streaming: { failureCallback: function(error) { // 直播流总是重试: if (player.isLive()) player.retryStreaming(); } } });

关闭重试的对应写法:

// v2.1 player.configure({ streaming: { infiniteRetriesForLiveStreams: false // 不重试直播 } }); // v2.4 player.configure({ streaming: { failureCallback: function(error) { // 什么都不做,即停止尝试流式传输该内容 } } });

streaming.infiniteRetriesForLiveStreams在 v2.2 被废弃、v2.3 被移除。新机制下,决策依据可以是player.isLive()error.code或任何其他信息;由于player.retryStreaming()可在任意时刻调用,你完全可以推迟决策——比如等用户反馈、等浏览器重新联网。

文档给出的几种典型回调策略:

function neverRetryCallback(error) {} function alwaysRetryCallback(error) { player.retryStreaming(); } function retryLiveOnFailureCallback(error) { if (player.isLive()) { player.retryStreaming(); } } function retryOnSpecificHttpErrorsCallback(error) { if (error.code == shaka.util.Error.Code.BAD_HTTP_STATUS) { var statusCode = error.data[1]; var retryCodes = [ 502, 503, 504, 520 ]; if (retryCodes.indexOf(statusCode) >= 0) { player.retryStreaming(); } } }

如果你更习惯通过error事件处理,也可以用event.preventDefault()完全跳过 failureCallback:

player.addEventListener('error', function(event) { // 自定义 error 事件逻辑 if (player.isLive() && event.error.code == shaka.util.Error.Code.BAD_HTTP_STATUS) { player.retryStreaming(); } // 该事件不再触发 failureCallback event.preventDefault(); });

当前仓库中 lib/player.js 的retryStreaming(retryDelaySeconds = 0.1)仅对 MEDIA_SOURCE 加载模式生效(loadMode_ == shaka.Player.LoadMode.MEDIA_SOURCE时调用streamingEngine_.retry()),且可传入以秒为单位的重试延迟。Player 的默认 failureCallback(lib/player.js)演示了 v2.4 之后的演进方向:对动态流(isDynamic())遇到BAD_HTTP_STATUS/HTTP_ERROR默认延迟 1 秒重试(低延迟模式下 0.1 秒)、TIMEOUT错误延迟 0.1 秒重试;而 VOD 流的流式失败视为致命错误不自动重试。另外 Player 内部还会监听浏览器的online事件,恢复联网后自动调用retryStreaming()恢复播放(lib/player.js)。

八、HLS 起始时间配置的移除

对于开始时间不为 t=0 的 HLS VOD 内容,v2.1 提供了manifest.hls.defaultTimeOffset配置来告知正确的起始时间。该配置在 v2.4 中已被移除——HLS 内容的起始时间现在可以从分段(segment)本身自动提取,无需任何配置。

这意味着升级到 v2.4 后,应用代码中针对manifest.hls.defaultTimeOffset的配置可以直接删除,由解析器自动完成起始时间的推导。

九、离线存储 API 变更

v2.1 中shaka.offline.Storage.remove()接收一个StoredContent实例;v2.4 改为接收StoredContent上的offlineUri字段(字符串):

// v2.1: storage.list().then(function(storedContentList) { var someContent = storedContentList[someIndex]; storage.remove(someContent); }); // v2.4: storage.list().then(function(storedContentList) { var someContent = storedContentList[someIndex]; storage.remove(someContent.offlineUri); });

旧参数形式在 v2.3 被废弃、v2.4 移除,所有使用离线存储的应用必须更新。仓库 lib/offline/storage.js 中remove(contentUri)的签名验证了这一点:它接收字符串 URI,内部通过shaka.offline.OfflineUri.parse解析并以isManifest()校验,非法 URI 会抛出MALFORMED_OFFLINE_URI错误。

十、语言与角色(Language and Role)选择

在 v2.1 语言选择方法的基础上,v2.4 新增了针对角色的方法:getAudioLanguagesAndRoles()getTextLanguagesAndRoles()。它们返回"语言/角色"组合对象数组,且语言选择方法支持用可选的第二个参数指定角色:

// v2.4: var languagesAndRoles = player.getAudioLanguagesAndRoles(); for (var i = 0; i < languagesAndRoles.length; ++i) { var combo = languagesAndRoles[i]; if (someSelector(combo)) { player.selectAudioLanguage(combo.language, combo.role); break; } }

这一能力与当前仓库的轨道模型一脉相承:shaka.extern.Track结构中的languageroles字段(externs/shaka/player.js)正是语言/角色组合的数据来源,而 Player 的轨道查询/选择接口(getAudioTracks()selectAudioTrack()getTextTracks()selectTextTrack()等,见 lib/player.js)继续承载"按用户偏好切换轨道"的职责。

十一、NetworkingEngine API 变更

v2.1 中shaka.net.NetworkingEngine.request()直接返回 Promise;v2.4 返回shakaExtern.IAbortableOperation实例,其中包含一个 Promise:

// v2.1: player.getNetworkingEngine().request(type, request).then((response) => { // ... }); // v2.4: let operation = player.getNetworkingEngine().request(type, request); // 用 operation.promise 获取响应 operation.promise.then((response) => { // ... }); // 也可在满足某个条件时中止操作 onSomeOtherCondition(() => { operation.abort(); });

v2.4 通过给request()的返回值附加.then.catch方法提供了向后兼容层,但该兼容层计划在 v2.5 移除,应用级请求建议尽快迁移到新 API。

从源码看,lib/net/networking_engine.js 的request(type, request, context)返回shaka.net.NetworkingEngine.PendingRequest(继承AbortableOperation),内部先执行带重试的请求,再通过.chain()串联 response filter 等阶段;当请求尚未开始就调用 abort 时,会以OPERATION_ABORTED拒绝。

十二、网络 scheme 插件 API 变更

v2.4 同时变更了网络 scheme 插件(自定义 URI 协议的请求插件)的 API:

  1. 插件返回shakaExtern.IAbortableOperation实例,官方建议使用shaka.util.AbortableOperation工具类。
  2. 新增第三个参数requestType用于标识请求类型(MANIFEST、SEGMENT、LICENSE 等),应用可据此实现差异化处理。
// v2.1 function fooPlugin(uri, request) { return new Promise((resolve, reject) => { // ... }); } shaka.net.NetworkingEngine.registerScheme('foo', fooPlugin); // v2.4 function fooPlugin(uri, request, requestType) { let rejectCallback = null; const promise = new Promise((resolve, reject) => { rejectCallback = reject; // 需要时使用 requestType,否则忽略 if (requestType == shaka.net.NetworkingEngine.RequestType.MANIFEST) { // ... } else { // ... } }); const abort = () => { // 中止底层操作 // ... // 拒绝 Promise rejectCallback(new shaka.util.Error( shaka.util.Error.Severity.RECOVERABLE, shaka.util.Error.Category.NETWORK, shaka.util.Error.Code.OPERATION_ABORTED)); }; return new shaka.util.AbortableOperation(promise, abort); } shaka.net.NetworkingEngine.registerScheme('foo', fooPlugin);

shaka.util.AbortableOperation的完整实现位于 lib/util/abortable_operation.js,除了构造函数(promise, onAbort)外,还提供若干静态工厂:failed(error)aborted()completed(value)notAbortable(promise)all(operations),以及用于串联异步阶段的实例方法chain(onSuccess, onError)finally(onFinal)aborted属性可查询操作是否已被中止(lib/util/abortable_operation.js)。

注意:旧的 Promise 风格 scheme 插件同样只在 v2.4 中保留兼容层,计划在 v2.5 移除。

十三、Manifest 解析器插件 API 变更

shaka.media.PresentationTimeline的接口发生两处重命名/签名变化,使用这些方法的ManifestParser插件必须同步更新:

  • setAvailabilityStart()更名为setUserSeekStart()
  • notifySegments()现在接收一个引用数组(reference array)和一个名为isFirstPeriod的布尔值,取代原来的 period 起始时间 + 引用数组两个参数。

这两处变更直接影响 DASH、HLS 等清单解析插件的实现,应用若自行编写 ManifestParser 插件,升级时务必检查对PresentationTimeline的调用是否命中上述方法。

十四、升级清单速查

以下为从 v2.1 迁移到 v2.4 时需要逐一核对的应用代码变更点:

变更领域v2.1 写法v2.4 写法迁移强度
文本命名空间shaka.media.TextEngineshaka.text.TextEngine.registerParser(...)必须
文本解析插件返回VTTCue,入参ArrayBuffer返回shaka.text.Cue,入参Uint8Array必须(无兼容层)
字幕显示仅浏览器渲染textDisplayFactory自定义渲染可选
ABR 配置abr.manager+setDefaultEstimate/setRestrictionsabrFactory+configure(AbrConfiguration)必须
ABR 接口chooseStreams()/switch(streamMap)chooseVariant()/switch(variant)必须
切换历史shakaExtern.StreamChoiceshakaExtern.TrackChoice(新增 bandwidth)读取方需适配
失败重试streaming.infiniteRetriesForLiveStreamsstreaming.failureCallback+player.retryStreaming()必须
HLS 起始时间manifest.hls.defaultTimeOffset自动从分段提取,配置移除删除配置
离线删除storage.remove(storedContent)storage.remove(storedContent.offlineUri)必须
语言/角色仅语言选择方法新增getAudioLanguagesAndRoles()新增能力
网络请求request()返回 Promise返回IAbortableOperation(含.promise/.abort()强烈建议
网络插件返回 Promise,(uri, request)返回AbortableOperation(uri, request, requestType)强烈建议
清单插件setAvailabilityStart()、旧notifySegments()setUserSeekStart()、新notifySegments(refs, isFirstPeriod)必须(若使用)

十五、延伸阅读

  • 升级文档系列:upgrade-v2.2-to-v2.4.md、upgrade-v2.3-to-v2.4.md,以及 v2.4 之后的 upgrade-v2.4-to-v2.5.md 与 upgrade-v2.5-to-v3.0.md。
  • ABR 默认实现:lib/abr/simple_abr_manager.js 与带宽估算器 lib/abr/ewma_bandwidth_estimator.js。
  • 文本引擎与 Cue:lib/text/text_engine.js、lib/text/cue.js。
  • 网络层:lib/net/networking_engine.js 与可中止操作工具 lib/util/abortable_operation.js。
  • 离线存储:lib/offline/storage.js。
  • 基础使用与配置:docs/tutorials/basic-usage.md、docs/tutorials/config.md。

【免费下载链接】shaka-playerJavaScript player library / DASH & HLS client / MSE-EME player项目地址: https://gitcode.com/GitHub_Trending/sh/shaka-player

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询