如何实现 OPPO 平板官网视频自动播放的效果?前提是不使用 video 标签来实现 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xyxc0673
V2EX    问与答

如何实现 OPPO 平板官网视频自动播放的效果?前提是不使用 video 标签来实现

  •  
  •   xyxc0673 2023-07-12 14:49:12 +08:00 1598 次点击
    这是一个创建于 823 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近在做一个需求,类似 OPPO 平板官网( https://www.oppo.com/cn/accessories/oppo-pad-2/ )的这个效果,我看它是使用 canvas 去实现的,然后在网络请求里也没有看到这个视频,我问 GPT 给到的回复都是在 video 标签播放时将视频帧画到 canvas 上,这样一来不就会下载这个视频?

    要如何做到不下载视频的情况下去画视频帧呢?

    至于为什么不使用 video 标签来自动播放是因为现代浏览器会对这样自动播放的行为进行拦截,报出这个错误:
    Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first.
    15 条回复    2023-07-12 19:33:51 +08:00
    bsfx2
        1
    bsfx2  
       2023-07-12 14:56:01 +08:00
    /content/dam/oppo/product-asset-library/accessory/oppo-pad-2/cn/v1/assets/ksp.flv
    Rache1
        2
    Rache1  
       2023-07-12 15:01:40 +08:00
    看起来是用了 WebAssembly 对 flv 进行解码,然后画到 canvas 上的
    xyxc0673
        3
    xyxc0673  
    OP
       2023-07-12 15:03:32 +08:00
    @Satelli 看来还是读取了视频,然后画到 canvas 上面的
    xyxc0673
        4
    xyxc0673  
    OP
       2023-07-12 15:04:36 +08:00
    @Rache1 请教一下从哪里可以看出使用了 WebAssembly 呢
    SummerGua
        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
    Rache1
        6
    Rache1  
       2023-07-12 15:10:30 +08:00   3
    @xyxc0673

    从 Network 看到 这个 flv 的请求记录,的发起者,然后看到这个 getPlayer



    点进去往下看一点儿,就有加载了个 wasm 的 video decode 插件



    ---

    我也不太确定,根据上下文猜的
    xyxc0673
        7
    xyxc0673  
    OP
       2023-07-12 15:23:44 +08:00
    @SummerGua
    @Rache1 #6

    赞,看到加载视频的这个代码了,确实是 wasm + canvas 实现,现在的问题变成了有没有类似的开源库可以用一用,不然就要从前端工程师变成 Rust 工程师了
    Rache1
        8
    Rache1  
       2023-07-12 15:38:56 +08:00   1
    喂饭级教学

    ---









    anguiao
        9
    anguiao  
       2023-07-12 15:48:06 +08:00
    所以为什么不能用 video 标签
    LinePro
        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 属性就不会拦截了。
    xyxc0673
        11
    xyxc0673  
    OP
       2023-07-12 18:23:09 +08:00
    @Rache1 #8 太感谢了,是我未曾设想的道路
    xyxc0673
        12
    xyxc0673  
    OP
       2023-07-12 18:25:10 +08:00
    @anguiao
    @LinePro

    我后来发现确实将视频静音之后就可以自动播放了,这个功能其实只是视频的预览,自动播放前 N 秒,点击自定义的播放按钮再弹窗播放,所以不希望用户能够控制这个预览,使用视频组件的话,可以通过右键控制视频。
    okakuyang
        13
    okakuyang  
       2023-07-12 18:49:07 +08:00 via iPhone
    自己解码效率并不高,没有特殊需求应该用 video
    bgm004
        14
    bgm004  
       2023-07-12 19:16:07 +08:00 via Android
    我是用 jsmpeg 做的,缺点就是 mp4 转 ts 格式后文件体积翻倍。
    FreeEx
        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);
    }
    });

    });

    }
    ```
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2929 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 00:19 PVG 08:19 LAX 17:19 JFK 20:19
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86