音视频面试题集锦第 15 期 | 编辑 SDK 架构 | 直播回声 | 播放器架构

文摘   科技   2024-01-24 08:00   上海  

我们在知识星球上创建的音视频技术社群关键帧的音视频开发圈已经运营了一段时间了,在这里大家可以一起交流和分享音视频技术知识和实战方案。我们会不定期整理一些音视频相关的面试题,汇集一份音视频面试题集锦(可进入免费订阅)。也会循序渐进地归纳总结音视频技术知识,绘制一幅音视频知识图谱(可进入免费订阅)

下面是第 15 期面试题精选:

  • 1、音视频编辑 SDK 一般包含哪些模块?各模块是什么职责?
  • 2、音视频编辑中转码流程 pipeline 的线程模型和缓冲区要怎么设计?
  • 3、直播中发现有回声,可能的原因是什么?
  • 4、如果让你设计一个播放器的架构,你会分哪几层?

1、音视频编辑 SDK 一般包含哪些模块?各模块是什么职责?

从业务角度来看,视频编辑 SDK 上层的功能模块通常包括:抽帧模块预览播放器模块转码模块

  • 转码模块主要负责将编辑态的音视频素材及相关效果编码和封装为目标视频。
  • 抽帧模块主要负责从视频素材中抽取图片用于缩略图、封面等场景。
  • 预览播放器模块则主要负责渲染播放编辑态的音视频素材及相关效果。

这里,我们重点说一下支持编辑能力的转码模块,为了支持编辑能力通常需要设计一套数据结构,一般包括如下概念:

  • Composition:最外层的数据结构。音视频编辑相关的数据结构都包含在其中,比如多音频视频轨道、片段信息。
  • Track:轨道。包括音频轨道、视频轨道等。
  • Segment:片段。包括指定时间的音频、视频的片段。
  • Timeline:时间线。时间线是各音视频及特效素材如何串起来的基准。

配合这套数据结构的细分功能模块有:

  • Reader:资源数据读取模块。按照数据结构层级可以封装对应的 CompositionReader、TrackReader、SegmentReader 等。在 Reader 中可以按需组装 Demuxer、Decoder、FrameFilter、Effect、Mixer、Speed 等模块,从资源文件中读取数据,并按照给定的参数进行处理并输出最终需要的帧数据。
  • Demuxer:解封装模块。
  • Decoder:解码模块。
  • FrameBuffer:帧缓冲区。用于不同模块在生产和消费对接时缓存数据。
  • FrameFilter:帧处理模块。可以跟进设定的参数进行丢帧、补帧,输出指定帧率的音视频数据。
  • Effect:特效处理模块。提供滤镜、特效效果等能力。
  • Mixer:音视频混合模块。不同层级的 Mixer 可以提供不同的功能,比如和 CompositionReader 协同的 Mixer 可以支持混音、画中画,和 TrackReader 协同的 Mixer 可以支持混音、转场等能力。
  • Speed:变速模块。用于处理编辑里对音频或视频进行变速处理。
  • Encoder:编码模块。
  • Muxer:封装模块。

更详细的编辑 SDK 的模块架构图,见我们的知识星球帖子:https://t.zsxq.com/16h36X77N[1]

2、音视频编辑中转码流程 pipeline 的线程模型和缓冲区要怎么设计?

这里我们可以将 Demuxer、Decoder 模块封装到 Reader 中,它们在一个线程中来处理数据读取、解封装、解码几个环节的工作,并将解码后的数据存入 FrameBuffer 缓冲区。

我们将 Encoder、Muxer 模块封装到 Writer 中,它们在一个线程中来处理编码、封装几个环节的工作。其中编码需要的数据通过一个回调向 Reader 要数据,在回调中,Reader 将其 FrameBuffer 中缓冲的数据喂给 Writer 的 Encoder 来进行编码。

上面的设计是一个比较简要的设计,这里还有一些经验可供参考:

  • Encoder 中我们会将 AudioEncoder、VideoEncoder 拆分开,各自一个线程。
  • AudioEncoder、VideoEncoder 输出的编码数据我们会在 Muxer 中做音视频交错和封装。
  • Decoder、Encoder 根据使用的具体软编解码器或硬编解码器的不同,可能会有自己的线程。
  • 在实践中,如果发现某个节点在 pipeline 中是瓶颈,可以考虑将其放在独立的线程中去,并配置对应的缓冲区,但是当线程过多时也会引入复杂性和问题。我们在之前就因为在 pipeline 中引入过多的线程不仅没有提升转码性能,反而带来了很多奇奇怪怪的问题,简化后,反而解决了不少问题。
  • 我们在实践中发现使用 Android Surface 编码时,如果用同步的方式,可能会出现编码卡住的情况:往编码器喂数据时,编码器由于内部缓冲区满了卡住,而由于是同步,编码好的数据未被取出,则缓冲区无法被清理导致数据始终喂不进去。所以,编码器最好做成异步的,并且由编码器主动去取数据。

更直观的转码流程 pipeline 图,见我们的知识星球帖子:https://t.zsxq.com/16PFkFene[2]

3、直播中发现有回声,可能的原因是什么?

直播中发现有回声,可能有如下原因:

  • 1、主播在直播的同时用其他设备看自己的直播并且声音外放,这种情况下,外放的直播间声音又被主播自己的麦克风采集再次传输到观众端,观众端连续听到直播间相同的声音,这就是一种回声,这种回声要经过直播延时、传输延时,整体延时可能会达到 6-10s 左右。
  • 2、主播在直播的同时用自己的手机外放音乐,这种情况下,如果这个音乐音频有被合成进直播流,而同时又由于音乐外放被麦克风采集到,这时候直播流中就会有两个音乐声,这两个音乐声有一定的延时,通常大概 1s 左右,这就会让直播观众听到回声。
  • 3、主播连麦也是容易产生回声的场景。主播 A 的声音传输到主播 B 端,主播 B 的设备如果外放连麦声音,就会将主播 A 的声音采集到再传回给主播 A,主播 A 收到这个声音就会听到自己刚才的说话声,这就是回声。如果还有观众在观看主播 A 的直播间,观众也会听到重复的主播 A 的声音,也是回声。这里需要注意的是虽然听到的是主播 A 的回声,但原因是其实是主播 B 端造成的。

4、如果让你设计一个播放器的架构,你会分哪几层?

我们可以分下面几层来设计播放器的架构:

  • 音视频核心层:职责在于处理网络协议、音视频解封装(Demuxer)、音视频解码(Decoder)、音视频数据结构封装等等,通常基于 FFmpeg 来实现。
  • 播放器内核层:基于音视频核心层的能力来封装播放器内核能力,包括使用多线程、多缓冲区串联网络、解封装、解码、渲染等节点;支持播放、暂停、seek、刷新数据源等控制能力;提供播放状态获取、播放事件回调、播放器错误上报等接口。
  • 播放器封装层:基于平台开发语言对播放器内核进行封装,提供高内聚低耦合的播放器接口。
  • 播放器工具层:在播放器核心能力的基础上组装和扩展其他播放相关的其他能力,比如:边下边播视频缓存能力、播放远程配置能力、播放数据埋点上报能力等等。
  • 播放业务控制层:基于业务属性进行播放策略控制,比如:码率选档、解码方式选择、网络链路优选等策略。

更多的音视频知识、面试题、技术方案干货可以进群来看:

扫描加入

参考资料

[1]

https://t.zsxq.com/16h36X77N: https://t.zsxq.com/16h36X77N

[2]

https://t.zsxq.com/16PFkFene: https://t.zsxq.com/16PFkFene


关键帧Keyframe
系统性地探索音视频、AIGC、区块链技术。
 最新文章