ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Shaka Player 从 v1 升级到 v2:完整 API 迁移指南与源码级解读

2026/9/16 18:36:03 拓冰建站 浏览量
Shaka Player 从 v1 升级到 v2:完整 API 迁移指南与源码级解读 Shaka Player 从 v1 升级到 v2完整 API 迁移指南与源码级解读【免费下载链接】shaka-playerJavaScript player library / DASH HLS client / MSE-EME player项目地址: https://gitcode.com/GitHub_Trending/sh/shaka-player导读本文基于 docs/upgrades/upgrade-v1-to-v2.md 编写是 Shaka Player 官方发布的 v1 → v2 详细迁移手册。升级到 v2 后播放器从需要手动构造各种 VideoSource 子类的架构转向了基于插件 统一 Player 配置的简洁模型。读完本文你将掌握load()、DRM 配置、音视频轨道选择、字幕加载、离线存储、网络过滤器等核心 API 在 v1 与 v2 之间的完整对应关系与迁移写法并能结合仓库源码理解 v2 设计的底层动机。一、v2 带来了什么版本特性总览v1 到 v2 是一次架构级重写官方文档列出的改进超过 30 项核心亮点包括更强的流媒体协议支持支持多 DASH Period、DASH Location 与 UTCTiming 时钟同步元素、Xlink、DASH trick mode、HLSVOD / Event / Live、MPEG-2 TS 全浏览器转封装transmux播放更简洁的 APIPlayer类从shaka.player.Player简化为shaka.Player不再需要 VideoSource 中间层更好的体验更低启动延迟、独立于播放/暂停的缓冲状态、跳过硬伤gap、从直播边缘负偏移开始播放、网络请求可中止、Fetch 优先于 XHR更强的可扩展性全新的插件与构建系统网络、清单解析、字幕解析全部插件化默认捆绑 HTTP、DASH、WebVTT 插件应用可自研插件并定制构建剔除不需要的默认插件更完善的 DRM 与字幕数值化错误码、区分字幕subtitle与隐藏字幕caption轨道、音频与文本语言偏好分离、未显示的字幕不预取、支持 TTML/VTT 区域、CEA 字幕离线能力升级离线受保护内容支持无持久化许可选项Demo 应用成为可离线的 PWA。注意以上均为官方 v2 发布时点的特性清单当前仓库已迭代至更新的 v3 版本如 docs/upgrades/upgrade-v2.5-to-v3.0.md 所示。本文聚焦 v1 → v2 的迁移语义涉及的具体 API 签名请以当前仓库 lib/player.js 源码为准。二、命名空间与插件架构2.1 命名空间简化v1 中播放器类名为shaka.player.Playerv2 简化为shaka.Player。这一改动贯穿所有 API 调用迁移时需全局替换。2.2 插件架构v2 采用比 v1 更干净的插件化架构网络、清单解析、字幕/隐藏字幕解析全部是插件。默认捆绑 HTTP 支持、DASH 支持与 WebVTT 三个插件官方计划在未来版本扩充。应用开发者可以自研插件并编译进库将插件保留在应用侧不入库通过定制构建剔除不需要的默认插件。插件的深入讨论见 docs/tutorials/plugins.md。三、load()方法告别 VideoSource3.1 v1 的用法v1 中必须先构造一个DashVideoSource或其他IVideoSource子类把清单 URL 传给构造函数再交给player.load()// v1: var player new shaka.player.Player(video); var videoSource new shaka.player.DashVideoSource(manifestUri); player.load(videoSource);3.2 v2 的用法v2 中整个 VideoSource 概念从 API 中消失直接传入 URL播放器根据文件扩展名或 MIME 类型自动选择清单解析插件// v2: var player new shaka.Player(video); player.load(manifestUri);从当前仓库源码看load()的签名已经进一步演进为load(assetUriOrPreloader, startTime null, mimeType)见 lib/player.js除了 URL 与可选的起始时间还支持第三个 MIME 类型参数以及传入PreloadManager实现预加载说明 v2 的由播放器自行决定解析方式这一设计被完整保留并持续扩展。另外注意 v2 文档明确提到构造Player时不再强制要求 video 元素新增了attach()与detach()方法用于管理播放器与 video 元素的挂接。四、ContentProtection 回调从必填到可选4.1 v1 的痛点v1 的DashVideoSource必须传入一个ContentProtection回调因为 Shaka v1 不解析 DASH 清单中的ContentProtection元素无法自动推导 license server URI。典型实现是对 schemeIdUri 做 UUID 匹配// v1: function interpretContentProtection(schemeIdUri, contentProtectionElement) { if (schemeIdUri.toLowerCase() urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed) { // 这是代表 Widevine 的 UUID。 return [{ keySystem: com.widevine.alpha, licenseServerUrl: https://proxy.uat.widevine.com/proxy }]; } else if (schemeIdUri.toLowerCase() urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95) { // 这是代表 PlayReady 的 UUID。 return [{ keySystem: com.microsoft.playready, licenseServerUrl: https://playready.directtaps.net/pr/svc/rightsmanager.asmx }]; } else { return null; } } var player new shaka.player.Player(video); var videoSource new shaka.player.DashVideoSource( manifestUri, interpretContentProtection); player.load(videoSource);4.2 v2 的标准方案configure()v2 中这些回调仅对非标准 ContentProtection 方案如 YouTube Demo 资源使用的自定义方案是必需的。对于使用标准方案的绝大多数场景无需任何回调直接configure()配置 license server 即可// v2: var player new shaka.Player(video); player.configure({ drm: { servers: { com.widevine.alpha: https://proxy.uat.widevine.com/proxy, com.microsoft.playready: https://playready.directtaps.net/pr/svc/rightsmanager.asmx } } }); player.load(manifestUri);注意上面 v2 示例中的服务器地址仅为官方文档演示用实际部署请替换为你自己的授权服务器地址。DRM 配置的完整讨论见 docs/tutorials/drm-config.md。4.3 自定义方案的迁移写法如需支持自定义 ContentProtection 方案v2 仍然支持回调但改由player.configure()注入且回调签名变为只接收contentProtectionElement// v2: function interpretContentProtection(contentProtectionElement) { if (contentProtectionElement.getAttribute(schemeIdUri) http://youtube.com/drm/2012/10/10) { var configs []; for (....) { configs.push({ keySystem: keySystem, // 注意v2 中叫 URI 而不是 URL licenseServerUri: licenseServerUri }); } return configs; } } var player new shaka.Player(video); player.configure({ manifest: { dash: { customScheme: interpretContentProtection } } }); player.load(manifestUri);两个细节值得注意一是字段名从licenseServerUrl变为licenseServerUri二是自定义方案可配置项在shakaExtern.DrmInfo中有完整定义对应 externs/shaka/drm_info.js。五、DrmInfo 细节EME 设置与网络过滤器分工5.1 v1 的大而全回调v1 的 ContentProtection 回调可以返回一个包含大量 EME 与 license 请求设置的详细 DrmInfo 对象// v1: function interpretContentProtection(schemeIdUri, contentProtectionElement) { if (schemeIdUri.toLowerCase() urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed) { return [{ keySystem: com.widevine.alpha, licenseServerUrl: https://proxy.uat.widevine.com/proxy, distinctiveIdentifierRequired: true, persistentStateRequired: false, serverCertificate: certificateUint8Array, audioRobustness: HW_SECURE_ALL, videoRobustness: HW_SECURE_ALL, initData: { initDataType: cenc, initData: initDataUint8Array }, licensePreProcessor: licensePreProcessor, licensePostProcessor: licensePostProcessor, withCredentials: true }]; } else { return null; } }5.2 v2 的分流drm.advanced 网络过滤器v2 将EME 相关设置迁移到配置对象的drm.advanced字段// v2: player.configure({ drm: { advanced: { com.widevine.alpha: { distinctiveIdentifierRequired: true, persistentStateRequired: true, serverCertificate: certificateUint8Array, audioRobustness: HW_SECURE_ALL, videoRobustness: HW_SECURE_ALL, // 注意initData 现在是一个或多个覆盖项的数组 initData: [{ initDataType: cenc, initData: initDataUint8Array }] } } } });其中initData由单个对象变为数组是明显的迁移陷阱。高级 DRM 配置详见 docs/tutorials/drm-config.md。而license 请求相关设置如licensePreProcessor、licensePostProcessor、withCredentials则迁移到 v2 的**网络过滤器Network Filters**体系。网络过滤器是覆盖所有网络请求含 license 请求与响应的通用过滤系统比 v1 的 preprocessor/postprocessor 更通用、更灵活也因此需要多写一点样板代码。在 v2 中处理 license 流量通常只剩两类需求使用跨站点凭据对应 v1 的withCredentials标志将 license 请求/响应包装或解包成其他格式。// v2: player.getNetworkingEngine().registerRequestFilter(licensePreProcessor); player.getNetworkingEngine().registerResponseFilter(licensePostProcessor); function licensePreProcessor(type, request) { // 这是作用于所有请求的通用过滤器因此按类型过滤出 LICENSE if (type ! shaka.net.NetworkingEngine.RequestType.LICENSE) return; // 等价于 v1 的 withCredentials: true request.allowCrossSiteCredentials true; // 包装请求数据这是一个 ArrayBuffer var newData wrapLicenseRequest(request.data); request.data newData; // 添加一个请求头 request.headers[foo] bar; } function licensePostProcessor(type, response) { // 这是作用于所有响应的通用过滤器因此按类型过滤出 LICENSE if (type ! shaka.net.NetworkingEngine.RequestType.LICENSE) return; // 解包响应数据这是一个 ArrayBuffer使用/保存额外数据 var rawLicense unwrapLicense(response.data); // 不再 return而是把原始 license 写回响应对象 response.data rawLicense; // 不返回任何东西。 }从当前仓库源码看registerRequestFilter/registerResponseFilter/unregisterRequestFilter/unregisterResponseFilter正是 lib/net/networking_engine.js 中NetworkingEngine的公开方法过滤器体系在后续版本中持续沿用。请求与响应过滤器的完整契约定义可参考shaka.net.NetworkingEngine.RequestFilter、shakaExtern.Request、shaka.net.NetworkingEngine.ResponseFilter与shakaExtern.Response的类型文档。六、ClearKey 配置从手搓 JWK 到一键配置v1 也能通过 ContentProtection 回调使用 ClearKey但必须手工构造 data URI 与伪造 init data// v1: function interpretContentProtection(schemeIdUri, contentProtectionElement) { var keyid; // 类型为 Uint8Array var key; // 类型为 Uint8Array var keyObj { kty: oct, kid: Uint8ArrayUtils.toBase64(keyid, false), k: Uint8ArrayUtils.toBase64(key, false) }; var jwkSet {keys: [keyObj]}; var license JSON.stringify(jwkSet); var initData { initData: keyid, initDataType: webm }; var licenseServerUrl data:application/json;base64, window.btoa(license); return [{ keySystem: org.w3.clearkey, licenseServerUrl: licenseServerUrl, initData: initData }]; }v2 通过player.configure()一步到位只需提供 keyid → key 的映射均为十六进制字符串// v2: player.configure({ drm: { clearKeys: { deadbeefdeadbeefdeadbeefdeadbeef: 18675309186753091867530918675309, 02030507011013017019023029031037: 03050701302303204201080425098033 } } });当前仓库的 lib/player.js 中仍有drm.clearKeys配置的解析逻辑播放器会将 clearKeys 转为 Map并在 stream 携带 DRM 信息且clearKeys为空时才走真实 license 流程确认了这一简化的 ClearKey 路径在后续版本中一直被保留。ClearKey 详细配置见 docs/tutorials/drm-config.md。七、带宽估计与 ABRBandwidthEstimator 并入 AbrManagerv1 的DashVideoSource接受应用注入的自定义 BandwidthEstimator 与 AbrManager 实现官方甚至推荐注入 BandwidthEstimator 以在多次播放间持久化带宽估计// v1: var player new shaka.player.Player(video); var bandwidthEstimator new shaka.util.EWMABandwidthEstimator(); var abrManager new shaka.media.SimpleAbrManager(); var videoSource new shaka.player.DashVideoSource( manifestUri, /* interpretContentProtection */ null, estimator, abrManager); player.load(videoSource);v2 将 BandwidthEstimator 的概念并入 AbrManager不再需要注入实例来持久化估计值自定义 AbrManager 通过player.configure()提供// v2: var player new shaka.Player(video); player.configure({ abrFactory: MyCustomAbrManager }); player.load(manifestUri);注意 v2 的配置项名是abrFactory工厂函数而非实例AbrManager 接口契约见shakaExtern.AbrManager。仓库中默认实现为 lib/abr/simple_abr_manager.js带宽估计器 lib/abr/ewma_bandwidth_estimator.js 与 lib/abr/ewma.js 仍在库中作为底层组件存在只是不再需要应用手动注入。八、轨道选择从三类轨道各自为政到variant 轨道8.1 v1按类型与 ID 操作v1 为每种轨道提供独立方法按 ID 选择// v1: var videoTracks player.getVideoTracks(); var i /* 自行选择一个下标 */; player.selectVideoTrack(videoTracks[i].id); // 注意传入的是 id特指 video8.2 v2variant 轨道模型v2 将音频与视频轨道合并为 variant 轨道。不能单独选择某个音频/视频流只能选择清单中定义的特定 variant。可用轨道通过getVariantTracks()与getTextTracks()获取切换轨道则调用selectVariantTrack()与selectTextTrack()并且传入整个轨道对象// v2: var variantTracks player.getVariantTracks(); var i /* 自行选择一个下标 */; player.selectVariantTrack(variantTracks[i]); // 传入整个轨道对象8.3 字幕显隐v1 用player.enableTextTrack()控制字幕显隐// v1: player.enableTextTrack(true);v2 改为player.setTextTrackVisibility()// v2: player.setTextTrackVisibility(true);所有轨道类型variant 与 text共用的数据结构定义在shakaExtern.Track。在 lib/player.js 中getVariantTracks()如 #L5689、selectVariantTrack()、getTextTracks()、selectTextTrack()这些方法在当前版本依然存在并且setTextTrackVisibility是setTextTrackVisibility_的公开导出包装。九、外挂字幕Side-loadingv1 需要在load()之前对DashVideoSource调用addExternalCaptions()// v1: var player new shaka.player.Player(video); var videoSource new shaka.player.DashVideoSource(manifestUri); videoSource.addExternalCaptions(textStreamUri, fr-CA, text/vtt); player.load(videoSource);v2 改为在load()完成后调用player.addTextTrack()并且显式指定字幕类型caption// v2: var player new shaka.Player(video); player.load(manifestUri).then(function() { player.addTextTrack(textStreamUri, fr-CA, caption, text/vtt); });v2 的addTextTrack(kind, lang, label, uri)与 v1 的addExternalCaptions(uri, lang, mimeType)相比参数顺序与含义均有变化迁移时务必对照新签名。十、播放起始时间v1 通过player.setPlaybackStartTime()设置任意起始时间且必须在load()之前调用// v1: player.setPlaybackStartTime(123.45); player.load(manifestUri);v2 改为load()的可选参数// v2: player.load(manifestUri, 123.45);当前仓库中load()的第二个参数startTime?number|Date正是这一设计的延续见 lib/player.js传入null/undefined时 VOD 从 0 开始、LIVE 从直播边缘开始。十一、Trick play变速播放v1 的player.setPlaybackRate()通过模拟video.playbackRate的负速率支持来变相实现 trick play。v2 的迁移规则很明确若你在 v1 中用setPlaybackRate()做 trick play请改用 v2 的player.trickPlay()其他场景直接使用video.playbackRate即可。当前仓库中trickPlay(rate, useTrickPlayTrack true)仍在 lib/player.js 存在第二个参数控制是否切换到专门的 trick play 轨道DASH trick mode配合文档中提到的DASH trick mode support特性。十二、configure()配置项对照表v1 与 v2 都有player.configure()但大多数设置在 v2 中位于不同的配置层级。官方给出的映射如下v1 配置项v2 对应配置项enableAdaptationabr.enabledstreamBufferSizestreaming.bufferingGoallicenseRequestTimeoutdrm.retryParameters.timeoutmpdRequestTimeoutmanifest.retryParameters.timeoutsegmentRequestTimeoutstreaming.retryParameters.timeoutpreferredLanguage拆分为preferredAudioLanguage与preferredTextLanguagerestrictionsrestrictions同名结构见下文liveStreamEndTimeoutv2 不再需要disableCacheBustingEvenThoughItMayAffectBandwidthEstimationv2 不再需要默认始终 cache-friendly关于限制restrictionsv1 的shaka.player.Restriction类型在 v2 中被简化为普通记录类型不再构造对象直接写匿名 JavaScript 对象即可。字段变化包括新增minPixels/maxPixels用于限制总像素数原来的minBandwidth/maxBandwidth拆分为minAudioBandwidth、maxAudioBandwidth、minVideoBandwidth、maxVideoBandwidth。完整字段见shakaExtern.Restrictions。v2 配置系统的完整文档见 docs/tutorials/config.md、docs/tutorials/network-and-buffering-config.md 与 docs/tutorials/drm-config.md。十三、getStats()统计结构全面调整v1 的getStats()返回以当前选中视频流为核心的流式统计// v1: player.getStats() Object streamStats: StreamStats // 指当前选中的视频流 videoWidth: number // 像素 videoHeight: number // 像素 videoMimeType: string videoBandwidth: number // 比特/秒 decodedFrames: number droppedFrames: number estimatedBandwidth: number // 比特/秒 playTime: number // 秒 bufferingTime: number // 秒 playbackLatency: number // 秒 bufferingHistory: Array // 开始缓冲的时间戳列表 bandwidthHistory: Array of Objects timestamp: number // 秒带宽估计生成时间 value: number // 带宽估计值比特/秒 streamHistory: Array of Objects timestamp: number // 秒视频流切换时间 value: StreamStats // 选中流的信息仅视频v2 不再暴露播放延迟playbackLatency与带宽估计历史switchHistory比 v1 的streamHistory更通用覆盖所有流类型// v2: player.getStats() Object width: number // 像素当前视频轨道 height: number // 像素当前视频轨道 streamBandwidth: number // 比特/秒当前所有流的总和 decodedFrames: number // 与 v1 相同 droppedFrames: number // 与 v1 相同 estimatedBandwidth: number // 比特/秒与 v1 相同 loadLatency: number, // load() 与视频 loadend 事件之间的秒数 playTime: number // 秒与 v1 相同 bufferingTime: number // 秒与 v1 相同 switchHistory: Array of Objects // 取代 v1 的 streamHistory timestamp: number // 秒流被选中的时间 id: number // 轨道 ID type: string // variant 或 text fromAdaptation: boolean // 区分 ABR 自动切换与手动选择 bandwidth: ?number // 轨道的带宽文本轨道为 null stateChange: Array of Objects timestamp: number // 秒状态变化时间 state: string // buffering, playing, paused 或 ended duration: number // 处于该状态的秒数getStats()在 lib/player.js 中仍存在v2 的完整统计结构定义见shakaExtern.Stats。十四、Player 事件对照表v1 与 v2 的Player都会发出事件但事件名、字段与错误表达方式差异巨大v1v2errorerrorerror.detail各种类型error.detailshaka.util.Errorerror.detail.type模糊的字符串error.detail.category数值无歧义的shaka.util.Error.Categoryerror.detail.message模糊的字符串error.detail.code数值无歧义的shaka.util.Error.CodebufferingStart与bufferingEnd合并为buffering布尔值进入缓冲为 true离开为 false无对应物texttrackvisibilityshaka.Player.TextTrackVisibilityEventtrackschangedtrackschangedseekrangechangedv2 无对应事件更新 UI 时改用player.seekRange()adaptationadaptationadaptation.contentType字符串v2 无对应字段adaptation.sizewidth:number, height:numberv2 无对应字段adaptation.bandwidthnumberv2 无对应字段核心变化是错误从模糊字符串升级为数值化的categorycode这正是 v2 特性清单中Numerical error code system与critical vs recoverable errors 指示的体现。shaka.util.Error的 Category / Severity 枚举定义在 lib/util/error.js。事件完整说明见shaka.Player文档的 Events 章节。十五、浏览器支持检测v1 使用shaka.player.Player.isBrowserSupported()// v1: if (!shaka.player.Player.isBrowserSupported()) { // 显示错误并中止。 }v2 保留了同名方法并新增了诊断用的probeSupport()。由于它需要向 EME 发起大量查询、可能触发用户授权弹窗官方建议仅用于诊断// v2: if (!shaka.Player.isBrowserSupported()) { // 显示错误并中止。 } else { // 仅在浏览器受支持时才调用此方法。 shaka.Player.probeSupport().then(function(support) { // 该检查是异步的因为 EME API 是异步的。 // support 对象包含浏览器能力的更多信息如需使用。 // 例如如果你同时要求 Widevine 与 WebM/VP9 if (!support.drm[com.widevine.alpha] || !support.media[video/webm; codecsvp9]) { // 显示错误并中止。 } }); }从当前仓库源码看probeSupport()的职责被拆解到各子系统DRM 侧在 lib/drm/drm_engine.js清单解析侧在 lib/media/manifest_parser.jsMediaSource 侧在 lib/media/media_source_engine.js最终由Player汇总为support对象。support 对象的完整结构见shakaExtern.SupportType仓库根目录还提供了 support.html 用于在浏览器中直接查看完整的probeSupport()报告。十六、HttpVideoSource被移除v2 中没有 v1 的HttpVideoSource对应物Shaka v2 只通过 MSEMedia Source Extensions播放。这大大简化了代码也让 Shaka 得以删除大量特例分支。如果你的应用此前依赖HttpVideoSource走非 MSE 路径迁移时只能接受 MSE 播放方式。十七、离线存储Offline Storage17.1 存储从OfflineVideoSource到Storage类v1 用OfflineVideoSource存储离线内容// v1: function chooseStreams() { return Promise.resolve(trackIds); } function onProgress(evt) { console.log(Stored evt.detail %); } var videoSource new shaka.player.OfflineVideoSource(null, null); videoSource.addEventListener(progress, onProgress); var promise videoSource.store(https://url, en-US, null, chooseStreams); promise.then(function(groupId) { console.log(Stored at group ID groupId); });v2 改用Storage类轨道选择与进度回调通过storage.configure()注入且支持携带应用自定义元数据{extra: data}// v2: function chooseTracks(allTracks) { return filteredTracks; } function onProgress(storedContent, percent) { console.log(Stored percent %); } var storage new shaka.offline.Storage(player); // 可选 storage.configure({ trackSelectionCallback: chooseTracks, progressCallback: onProgress }); var promise storage.store(https://url, {extra: data}); promise.then(function(storedContent) { console.log(Can be loaded using url: storedContent.offlineUri); });17.2 播放直接load(offlineUri)v1 仍需用OfflineVideoSource装载已存内容// v1: var videoSource new shaka.player.OfflineVideoSource(groupId, null); player.load(videoSource);v2 中只要知道 URL 即可不需要任何特殊类型。存储内容时你会得到一个特殊 URL像普通 URL 一样传给load// v2: player.load(offlineUri);17.3 列出与删除v1 用OfflineVideoSource的retrieveGroupIds()与deleteGroup()// v1: var videoSource new shaka.player.OfflineVideoSource(null, null); videoSource.retrieveGroupIds().then(function(groupIds) { console.log(groupIds[0]); }); var sourceToDelete new shaka.player.OfflineVideoSource(groupId, null); sourceToDelete.deleteGroup().then(function() { console.log(Done); });v2 统一由Storage的list()与remove()完成// v2: var storage new shaka.offline.Storage(player); storage.list().then(function(storedContents) { var firstInfo storedContents[0]; var url firstInfo.offlineUri; player.load(url); }); storage.remove(storedContent.offlineUri).then(function() { console.log(Done); });从当前仓库源码看lib/offline/storage.js 的Storage类完整保留了这一使用流程先构造Storage(player)再configure()回调随后按需调用store()/remove()/list()见该文件注释中的使用顺序说明以及configure()#L204、store(uri, appMetadata, mimeType, externalThumbnails, externalText)#L283等方法。v2 中存储即得到offlineUri、播放即load(offlineUri)的设计也延续至今。十八、迁移要点速查全局替换命名空间shaka.player.Player→shaka.Player所有shaka.player.*类型逐一检查。删除 VideoSource 中间层load()直接收 URLHttpVideoSource无替代仅支持 MSE。DRM 三处迁移license server 进drm.serversEME 高级设置进drm.advanced注意initData变数组请求包装/跨域凭据改用网络过滤器registerRequestFilter/registerResponseFilter。ClearKey 简化直接配置drm.clearKeys的十六进制 keyid→key 映射。ABR 注入方式变化abrFactory配工厂函数无需自行注入带宽估计器。轨道模型升级视频/音频合并为 variantselectVariantTrack(trackObject)传整个对象字幕显隐改setTextTrackVisibility()外挂字幕改addTextTrack()且需在load()之后调用。起始时间与 trick play起始时间并入load(uri, startTime)trick play 专用trickPlay()。配置层级重排按上文映射表迁移各超时、缓冲目标与语言偏好preferredLanguage拆分、restrictions字段重构。统计与事件getStats()结构大改无延迟、switchHistory覆盖全流类型错误从字符串升级为数值category/codebufferingStart/bufferingEnd合并为buffering布尔事件。浏览器检测增强isBrowserSupported()之外新增异步probeSupport()可用于细粒度能力探测如support.drm[com.widevine.alpha]、support.media[video/webm; codecsvp9]。离线 API 统一到Storagestore()/list()/remove()播放直接load(offlineUri)。如需在升级后继续跟进 API 演进仓库 docs/upgrades 目录下还提供了 v2.0→v2.4、v2.4→v3.0 等后续升级指南v2 的完整使用方式可结合 docs/tutorials/config.md、docs/tutorials/drm-config.md、docs/tutorials/plugins.md 与 docs/tutorials/offline.md 继续深入。【免费下载链接】shaka-playerJavaScript player library / DASH HLS client / MSE-EME player项目地址: https://gitcode.com/GitHub_Trending/sh/shaka-player创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考