W3C

Web 中文兴趣组会议

2022年9月6日

题目:video 的 SEI 规范提议

讲者:付宇豪(字节跳动)[演示文稿]

现场纪要

付宇豪:

我是来自字节的宇豪,现在做一些Web RCT相关的场景,在工作当中会遇到很多SEI与视频流传输相配合的规范。发现从Web的视角好像没有一个相应的规范规定怎么获取解析SEI,还是我们应用层来做。当时也遇到了一些浏览器实现上的限制,把这个限制同步给产品经理之后,产品经理说“你看我这个需求再提给谁?”我想了办法,我们还是从规范的角度把SEI的事情从浏览器层面能不能给我们提供规范的接口,所以就有了后面我向W3C一起聊这个事情,也包括今天来分享SEI规范提议包含的东西。

首先,我分享主要是四个部分:首先是介绍一下视频中的SEI;然后讲讲缺少规范给我们日常开发带来的困扰,还有一些正在推进过程中的规范与讨论。最后就是一个理想的规范定义。

一、什么是SEI

首先介绍一下什么SEI,可能做视频的同学会比较了解,它的全称是Supplemetal Enhancement Infromation,也就是视频中相关的信息,会丢失一部分信息,这部分信息不会导致无法解码,但会丢失一些信息,在264和265规范当中有支持,从定稿的266规范当中也有支持,所以它是贯穿了H26X的编码集。

它携带的信息类型比较多,我们业务当中常用的是oX05,也就是用户自定义的信息。

SEI通常会用到什么地方呢?不知道大家是否逛视频网站,就是是个防挡弹幕,人像先出来,人像有一个蒙版,不会被阻挡,蒙板需要根据视频信息去遮挡,也就是说每一帧和蒙版都有关系,SEI就是很好的方式携带它,从视频的容器角度也有办法,但没有SEI这么直接。

不知道大家是否玩过百万英雄答题,当主播喊“3、2、1开题板”,大家在的题板在之后都打开了,每个人的题板并不相同,但不可能存在主持人喊3、2、1之后打不开,所以它也是基于SEI的方式打开,因为任何的旁路都无法保证延迟和信令之间是同步的,这也是典型的应用场景。

做直播过程中还有一个应用场景,就是端到端延迟。

中间需要时钟服务在两端做校准,没有SEI就很难校准两者之间的时间,这就是SEI在时钟中的使用。

如果直播当中,有一些实时的字幕,这些实时字幕也需要视频流下发,因为他说话时间和人匹配。但我们知道直播流的分发,转码服务不可能受旁路的干扰或者耦合,所以它会把音频流翻译出去,做到和视频之间的应用。

也就是说它和视频之间的同步,中间也有一个基于SEI的推流时间,可以在两个旁路之间形成对应关系。

二、缺少规范带来的困扰

接下来看看缺少规范给我们带来的困扰。首先,考虑一个常见Web播放流程。如果大家熟悉的话就知道,从Web的角度,从CDN拉到视频流之后,会经过一次转封装,呈FMP4的格式转发得Media Source,再通过Media Source给Video,Video可以读到FMP4的buff,做解析、解码。

缺少规范支持,现在做SEI解析,就是从转封装这一层,解析的时候拿到Video的时间,相对于Video的时间,这也是算出来的。因为视频流动时间戳不是以秒为单位,我们需要基于它算出一个SEI基于Video元素播放的事件,再缓存到一个列表,在Video 的timeupdata事件,基于time updata的事件,因为它是从FMP4转封装过来,而且用户能触达的前半部分在浏览器,后面部分Video是业务的东西,和业务之间又有代码的耦合,这也不一定。

还有一个特别痛苦的事情,因为Safari不支持Media Source,这就导致拿不到这个流,也就是拿不到SEI的数据。所以刚开始我们聊的几个场景,目前都没有办法在iOS Safari上使用。

因为它不仅是iPhone手机上的Safari,它意味着无法做视频流播放,如果强行拆成两个旁路来做,因为你知道的是Video播放的时间,但并不真正渲染到了哪一帧,所以SEI也无法做同步渲染。

介绍了一些缺乏规范带来的困扰,接下来就是尝试总规范上解决问题。

三、推进中的规范与讨论

当时我找到了W3C,希望制定了SEI event,我期望是直接在Video上暴露一个事件,能够把SEI的内容通过一个事件结构体暴露给我,我在Video的事件回调里,能够通过一个列表维护起来,还是可以在接收一定精度的情况下,用time update的Video,这样可以满足任何视频流分发或者解析的方式。无论是用Media Source,还是用iOS、Video.src,因为Video内部也有解析代码,也就是不用再区分iOS上有个方案或者安卓,或者其他的外部应用有不同的方案,大家都是一样的。

当然Web RTC不一样,但是今天不在这里讨论。

这样做的话有一个限制,有一个回调。我见过一些应用在SEI事情上,把SEI打得特别频繁。如果事件逐帧打SEI,每个视频帧都放一个SEI,事件可能调用比较频繁,会导致一些问题,这也是这个事件的限制。还有刚才提到的上述代码存在选吗的问题,因为time update是24毫秒触发一次。

首先解决精度的问题,它有一个HTML Video ElementbrequesVideoFrame callback,这样我们可以得到比较好的渲染准确度。

如果我们使用VideoFrame callback,就可以从中间拿到一个Media time,根据之前缓存的SEI列表,可以得到一个相对准确的同步回执。

整个SEI这样做的好处就是前面的链路流程不用关注了,直接把SEI交给Video,从Video侧都可以收到SEI事件,通过 RVFC callback,就可以在Video层完成同步绘制的工作,不需要从播放器转封装的处理层做事情了,相对比较闭环,这是SEI event提案比较大的优势。

他们说这个规范特别适合和DataCue玩,DataCue是指带内、带外的数据,这里有的是字幕的信息,有的是FMP4盒子捡SMG,也是消息的形式,可以把各种形式抽象出来成抽象的meta data,映射到Video匀速播放的时间点上,通过监听一个track,一个cue是一个时间点,通过cue就知道一个时间点加入了,可以通过active Cues就可以知道时机。

这个规范设计本身有一些是为了字幕设计,字幕有字幕进入和退出,对于SEI来说,用这个规范也可以,Cue的时间比较短,也可以。它还带来了一个active Cues的属性,如果觉得回调触发时间比较短,还可以获取cue的列表,知道SEI的数据存在,这时候可以做批量消费,不用数据回调,就是之前提到的极端场景,每个视频帧打一个SEI,意味着一秒钟出发30~60次,会干扰主线程的任务,用这个规范会更好。这是基于track的抽象方式,以及基于active Cues的能力,所以后面这个规范可以加入一起讨论。

今天还有很多WebCodecs的规范,WebCodecs是可以交给浏览器实际帧的编解码,所以在WebCodecs里也有这样的讨论,能不能从WebCodecs编解码过程中获取视频的元数据,包括SEI、SPS、VUI,现在讨论是希望解码过程中获取这些信息。

因为SEI解析并发生在解码阶段,在解析264帧的时候就可以获取这些信息,所以我认为可以在WebCodecs智能构件的时候,其实做完SEI就可以拿到信息,如果有关键帧,SPS、VUI信息也可以暴露出来。因为解码之后,可以把Video关注到Video Frame,因为渲染链路可能不是Video,基于Video Frame之后可以做渲染,就可以和SEI做精确的渲染,这是后面结合WebCodecs,SEI如何暴露的问题,这个问题后面会继续做讨论。

四、理想的规范定义

最后简单讲一下我认为规范比较理想的规范定义的样子,后面会从设计上讨论和考虑的。

首先,之所以提SEI的初衷,除了实在不能解决的,比如iOS safrai不能解决Media Source的问题。他们提出是不是可以做一个规范解决这个问题,我想了流媒体还是比较困难,我们是不是可以从应用层把处理的复杂性隐藏下来,因为本身Video也在做这件事,可以把复杂性放到平台层,这是一个出发点之一。

第二点,解析的时候拿到SEI,因为SEI还涉及到一些推理或者其他,包含的信息不是立即能渲染消费,可能要交给应用层处理,留给他处理时间,也就是解析到渲染时间之内都可以留给应用层解决SEI的数据。

第三点,我们要对不同渲染精度提供不同渲染方案,用WebCodecs可能是比较高精度,如果不追求精度,也可以使用time update,后还是希望兼容Video.src的播放方式,这样就可以兼容到所有的平台。

稍微展开一点,就是应用的处理时机。因为作为直播这种情况,在接到SEI数据的时候,还有大量的时间,直播的延迟在播放器的水位,可能还有秒级的时间交给应用处理SEI数据,我认为这个时间是足够的。所以可以在带解码,也就是最深的帧,以及解码时间的秒级之内都可以做SEI的处理,这就是给应用比较好的处理时机。

如果设计的话,可能会考虑到这一点。然后不同精度的处理方案,给不同的诉求,给不同的SEI定义,包括精确渲染、频繁触发,以及对上述两个没有要求可以单独使用,单独的SEI event和WebCodecs都可以。

前面听了大家的分享之后,有一些新的想法。认为这是一个更大的课题,信息需要随着视频流解析渲染的话题,未来可能不仅是SEI的事情,我们做RCT的过程中也遇到不能解析的问题,它也是跟随视频信息做同步的能力,后面可能会用更抽象的方式去提问题。这可能是后面的计划。

OK,今天的分享就是这些,谢谢大家!

提问:我想问一下SEI帧的去重是在哪里?

付宇豪:它是哪种传输场景,目前没有遇到丢的,除非是不可靠传输发现丢包了,比如是可靠传输,视频帧里的内容不会丢的。如果是不可靠,也没有通过x2个的方式去防止,这可能是冗余的设计。

提问:在SEI帧里,如果在编码的时候分率下降或者升高了,里面SEI的信息是怎么样合并或者分解的?

付宇豪:我认为SEI并部分需要具备合并和分解的,它比较原子,就是这一帧编码要不要往里注入一个SEI是可控的。帧率下降了,首先并不需要在每一帧打入一个SEI,大部分情况下它在关键的帧打入SEI就可以了。所以帧率下降对这个事影响不大,至少从我们的场景看是这样。

提问:中间过程中,比如拿到打好的视频流,再做一次编码的处理,是不是就会碰到这个问题?

付宇豪:这个问题可能存在,需要配置相关的策略。如果SEI帧率不相同,可能存在丢弃的问题,比如之前是30后面变成15,如果之间逐帧打的话,就存在这个问题。所以,我还是建议不要逐帧打,如果只是关键帧,问题可能小一点。

付宇豪:目前的API定义里,是可以在canvas上渲染,但解析SEI还没有定义,这也是后面要推进的事情。在我看来最好不要在解码时候出SEI,因为可能慢了,因为解析出帧之后,一般应用只会有几帧的缓存,就要拿这个东西去渲染,如果SEI渲染很简单是可以这样做的。但有时候数据要拿到消费链路里,这种情况下就不需要在解码之后再出SEI了,这也是之前讨论的问题。然后,第二个问题,WebCodecs API编码时,是否可以在视频数据中插入SEI?可以。编码之后可以对264帧做处理,这并不需要WebCodecs为你做特别的处理。但如果我们希望应用感知这个事情的时候,WebCodecs再加一个编码API上打一些额外的数据进去,我觉得也是有用的,但打入的数据是不是不受限制,打入任何数据,这可能需要关注一下,因为打入的数据可能也会干扰到264的解析。目前没有这样的API,但可以手动做这个事情,可以拿到WebCodecs里塞一个SEI,这是可以的。


返回[会议总结页面]获取其他话题的会议纪要。

若您对上述内容有任何疑问或需进一步协助,请联系:会议主办方 W3C 北航总部 <team-beihang-events@w3.org>。