1
Satelli 2023-07-12 14:56:01 +08:00
/content/dam/oppo/product-asset-library/accessory/oppo-pad-2/cn/v1/assets/ksp.flv
|
2
Rache1 2023-07-12 15:01:40 +08:00
看起来是用了 WebAssembly 对 flv 进行解码,然后画到 canvas 上的
|
5
SummerGua 2023-07-12 15:05:57 +08:00
网络请求中是有该视频的
名称:ksp.flv 请求 URL: https://www.oppo.com/content/dam/oppo/product-asset-library/accessory/oppo-pad-2/cn/v1/assets/ksp.flv 请求方法: GET |
6
Rache1 2023-07-12 15:10:30 +08:00 3
@xyxc0673
从 Network 看到 这个 flv 的请求记录,的发起者,然后看到这个 getPlayer 点进去往下看一点儿,就有加载了个 wasm 的 video decode 插件 --- 🐶 我也不太确定,根据上下文猜的 |
7
xyxc0673 OP |
8
Rache1 2023-07-12 15:38:56 +08:00 1
|
9
anguiao 2023-07-12 15:48:06 +08:00
所以为什么不能用 video 标签🤔
|
10
LinePro 2023-07-12 16:27:22 +08:00 1
> 至于为什么不使用 video 标签来自动播放是因为现代浏览器会对这样自动播放的行为进行拦截,报出这个错误:
> Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first. 实际上目前版本的浏览器只会对有声音的视频自动播放按策略进行拦截。video 标签设置 muted 属性就不会拦截了。 |
12
xyxc0673 OP |
13
okakuyang 2023-07-12 18:49:07 +08:00 via iPhone
自己解码效率并不高,没有特殊需求应该用 video
|
14
Track13 2023-07-12 19:16:07 +08:00 via Android
我是用 jsmpeg 做的,缺点就是 mp4 转 ts 格式后文件体积翻倍。
|
15
FreeEx 2023-07-12 19:33:51 +08:00
看了一下源码,播放的并不是视频,而是一个类似 GIF 的东西。因为后缀是 mp4 的时候调用的是 remove ,反之将 canvas 传入了一个对象中。
让 AI 反混淆后的源码如下: ``` function getPlayer(element, container, options, autoplay = false, placeholder, startTime) { return new Promise(resolve => { let compatibilityLevel; const canvas = container.querySelector('canvas'); const img = container.querySelector('img'); const video = container.querySelector('video'); if (!this.isSupported || placeholder || (compatibilityLevel = this.app.plgs.fps?.compatLevel) > 0) { // 如果不支持或需要占位图,则删除 video 和 canvas 元素 canvas.remove(); video?.remove(); resolve(new Player(null)); return; } Promise.all([ new Promise(resolve => { // 检查兼容性 const level = this.app.plgs.fps?.compatLevel; if (level === undefined) { resolve(0); } else if (level > -1) { resolve(level); } // 监听兼容性变化 window.addEventListener(COMPAT_EVENT, ({detail: {level}}) => { resolve(level); }); }), new Promise(resolve => this.onReady(() => resolve())) ]).then(() => { let src = this.app.isPc() ? element.dataSrcPc : element.dataSrcMo || element.dataSrc; if (this.app.isPad() && element.dataSrcPad) { src = element.dataSrcPad; } if (!src) { throw new Error('Video source not specified'); } if (src.endsWith('mp4')) { // MP4 视频 if (条件 1 && 条件 2) { // 不支持,删除元素 canvas.remove(); video?.remove(); resolve(new Player(null)); return; } // 删除图片占位符 img.remove(); // 初始化视频 resolve(new Player(video)); video && this.initVideoWithOptions(video, container, src, options); return; } else { // GIF animation video?.remove(); const player = new GifPlayer(src, this.manager, canvas, options); if (!autoplay && !startTime) { // 显示占位图像 img.remove(); } else if (autoplay) { // 自动播放时删除占位图 player.onFirstFrame(() => { img.remove(); }); } else if (startTime) { // 指定 startTime 时删除占位图并 seek 到指定时间 img.remove(); player.seek(startTime); } this.players.push(player); resolve(player); } }); }); } ``` |