V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
LancerComet
V2EX  ›  分享创造

使用了一年多的另一个 SVGA Web 播放器现分享给大家

  •  
  •   LancerComet ·
    LancerComet · 2020-08-24 17:09:02 +08:00 · 2469 次点击
    这是一个创建于 1588 天前的主题,其中的信息可能已经有所发展或是发生改变。

    SVGA

    SVGA ( https://svga.io) 是 YY 研发的一套很棒的动画方案,这个方案在公司内大规模使用,因为是一套从设计到研发一套打通的方案,所以效率和整体体验都算不错.

    不过官方的 Web 版播放器使用起来有几个痛点:

    1. SVGA 最初应该没有考虑太多的流程控制,不过现实业务中经常性的是通过多个 SVGA 组合进行逻辑动画播放,比如 A 播 XX 帧之后再播放 B,然后再播放 C ;或者 A 原地 n 到 m 帧循环,用户点击后跳转到 p 帧播一次;官方的 API 在处理这个情景上不是那么自然,当场景复杂了之后需要写额外的封装处理.

    2. 官方播放器提供了多种缩放模式,但使用起来有些别扭,而且没有办法使用 CSS 样式控制舞台尺寸,当使用 CSS 设定宽高时舞台内容会出现没有规律的奇怪变形,灵活性稍微差了点,我们平常使用 CSS 的 scale 来处理.

    3. 某些版本的 IOS 平台会发热(现可能已修复)

    针对以上问题,去年年中的时候就决定重新编写一套新的 SVGA 播放器给内部使用,希望能够解决上面三个问题。经过一年多的修改和生产环境验证,目前个人认为可以分享出来和使用 SVGA 的朋友一起使用(说来也巧,官方的 Lite 版播放器差不多也是这个时候开始编写,有点撞车)

    处理痛点

    问题 1

    针对第一个问题,我们假设一个场景:载入一个 SVGA 文件后播放两段动画,第一段先播 10 帧,然后播放完成后再播 10 帧

    // 官方 SVGA Web 播放器播放两段动画.
    
    const parser = new SVGA.Parser('#stage')
    const player = new SVGA.Player('#stage')
    
    player.onload('/file.svga', videoItem => {
      player.setVideoItem(videoItem)
      
      let isSection2Played = false
      
      player.onFinished(() => {
        if (!isSection2Played) {
          playSection2()
          isSection2Played = true
        } else {
          console.log('done')
        }
      })
      
      playSection1()
    })
    
    function playSection1 () {
      player.startAnimationWithRange({
        location: 0,
        length: 10
      })
    }
    
    function playSection2 () {
      player.startAnimationWithRange({
        location: 10,
        length: 10
      })
    }
    

    我们实践下来当业务复杂时,需要外层再写一层封装来帮助进行流程控制,否则会比较别扭,要手工使用变量维护播放状态.

    对于业务来说,个人理想中的 API 应该是类似这样:

    // SVGAPlus 播放两段动画.
    
    import { SVGAPlus } from '@svgaplus/core'
    
    const player = new SVGAPlus({
      element: document.querySelector('#stage'),
      buffer: await SVGAPlus.loadSvgaFile('/file.svga')
    })
    
    await player.init()
    await player.playOnce(0, 9)
    await player.playOnce(10, 19)
    console.log('done')
    

    将状态控制保持在播放器内部,使得业务在使用时无需自行维护一套状态,同时 API 应当保持一种形式同步,来消弱心智负担.

    问题 2

    针对第二个问题,其实不需要做什么特殊处理,也不用提供缩放 API,舞台( Canvas )的缩放让业务方在外部直接使用 css 进行设置,这样行为和 是完全一致的,毕竟对于切图仔来讲图片的 css 样式是刻在基因中的,设计其他 API 反而有点复杂.

    <!-- 直接使用样式表控制尺寸才是追吼的. -->
    <canvas width="1200" height="1800" style="width: 300px"></canvas>
    

    问题 3

    针对第三个问题,最早遇到这个问题时个人在业务中复写了 requestAnimationFrame 方法,在 IOS 平台下限制执行频率来降低手机发热;当自己在编写这套新的播放器时,用于控制绘制的 Ticker 本身可设定帧率,所以原本打算使用这个特性为 IOS 做限制,但使用下来发现就算使用满帧率绘制也没有发生严重的发热问题,所以应该是官方某个版本中有些小问题,现在应该已经修复了吧.

    其他的呢

    Worker Parser

    我们在业务中发现当页面足够复杂时,页面其他逻辑加上 SVGA 的初始化逻辑可能会使得界面阻塞,所以对 SVGA 的 Parser 加入了 Worker 支持,将吃资源的初始化逻辑放入 Worker 中执行来保证主线程通畅. 这个特性是可选的,因为 Worker 会增加一些初始化时间,在简单的页面中依然可以使用主线程进行解析来保证加载速度.

    Pixi Renderer

    我们后来加入了一个叫做 PixiRenderer 的模块,使用 Pixi.js 代替原生 Canvas API (个人称之为 VanillaRenderer) 进行渲染,这样就得到了 Pixi 的所有好处,比如 WebGL 加持、自定义 Shader 、滤镜、叠加其他 Sprite 等特性,给胡乱瞎搞打下了坚实的基础.

    import { SVGAPlus } from '@svgaplus/core'
    import { PixiRenderer } from '@svgaplus/renderer.pixi'
    import * as Filters from 'pixi-filters'
    
    const player = new SVGAPlus({
      element: document.querySelector('#stage'),
      buffer: await SVGAPlus.loadSvgaFile('/file.svga'),
      renderer: PixiRenderer
    })
    
    await player.init()
    
    // Pixi 的 App 和 Container 可以这样访问:
    // player.renderer.pixiApp
    // player.renderer.pixiContainer
    
    // 瞎搞个滤镜瞅瞅.
    player.renderer.pixiContainer.filters = [
      new Filters.RGBSplitFilter()
    ]
    
    player.play()
    

    更多的信息

    官方播放器给的信息有时候不够用,所以这次将更多的信息暴露了出来.

    SVGAPlus

    个人起名为 SVGAPlus,只是希望解决一些问题,毕竟平平淡淡才是真,解决问题才算好.

    欢迎大家一起贡献: https://github.com/SVGAPlus/SVGAPlus

    请注意

    SVGAPlus 没有实现 SVGA 的一些特性,比如音频播放,因为我们在播放音频 + 视频的场景都是直接使用 .mp4 ,个人也比较推荐使用视频这样的通用做法.

    3 条回复    2020-08-25 11:00:55 +08:00
    LawlietZ
        1
    LawlietZ  
       2020-08-25 10:28:48 +08:00
    不错
    LawlietZ
        2
    LawlietZ  
       2020-08-25 10:33:16 +08:00
    话说这种可以实现透明视频,svga 是新格式吧,该怎么导出呢
    LancerComet
        3
    LancerComet  
    OP
       2020-08-25 11:00:55 +08:00
    @LawlietZ 是可以实现透明效果,SVGA 本质就是一堆 PNG / SVG 然后再加上帧信息,通过 AE 做完之后使用插件导出 https://svga.io/designer.html
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2752 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 12:14 · PVG 20:14 · LAX 04:14 · JFK 07:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.