【活动回顾】用 Elixir 开发 HLS 直播后端服务

Tubi 赞助与组织的第八期 Elixir Meetup 于上周六顺利结束,三位 Elixir 资深使用者 Horvo、Scott 和杨淼,与 660 多名线上线下的函数式编程爱好者分享了 Elixir 的相关应用与实践经验。本文回顾了第一场分享“用 Elixir 开发 HLS 直播后端服务”,本次分享由 Tubi 高级后端工程师 Horvo 主讲。

欢迎关注比图科技公众号,我们将发布 Elixir Meetup 另外两场的分享回顾。


下方笔记来自现场观众刘郎:

作为一个在线流媒体内容提供商,Tubi 为用户提供了广泛的内容选择,包括电影电视剧的点播以及传统电视台节目的在线直播。而在这些内容背后,Tubi 不走平凡路地选择了 Elixir 来实现这些内容的后端支撑。本次 Meetup 的第一个分享,正是 Tubi 高级工程师 Horvo 带来的“ Elixir 在 Tubi 直播后端服务的应用”。

Why HLS

HTTP Live Streaming (aka, HLS) 是用于在互联网上传输音视频的流媒体传输协议,由 Apple Inc. 在 2009 年提出,由于底层基于 HTTP:

- 它迎合了大部分防火墙的默认设置(相比 TCP 1935 端口的 RTMP 需求)

- 可以使用 HTTP 关键基础设施,如全球 CDN 网络(即使是 Nginx-rtmp-module 也因为更容易进行扩展,支持 HLS 视频播放)

- 良好的平台和设备兼容性( HTTP-FLV 依赖于第三方工具,如 BiliBili 开发的 flv.js;而 MPEG-DASH 没有 iOS 原生支持)这些特性使得 HLS 在和 RTMP、MPEG-DASH 等协议的比较中脱颖而出,并在 Tubi 直播业务中被选择和使用。

Your Own Elixir TV

为了让我们更好地理解 Elixir 在 Tubi 直播业务流程中的应用,Horvo 现场演示了如何从零开始搭建 Elixir TV,准备带领观众在全民直播的大潮中体验一番 。

整个 Elixir TV 系统分成以下几个部分:

Transcoder

接受原始的 MP4 等格式视频文件,在 Elixir 代码中调用 FFmpeg 命令(把专业的事儿交给专业的工具 ),根据提前定义好的目标码率,生成视频文件对应的多码率 Segment。这一步的重点是定义好 Data Schema,这部分定义会在各个模块间传递信息时被使用。

Scheduler

Scheduler 是 Elixir TV 的核心模块。区别于传统的 Video on Demand (VOD)点播平台仅仅需将静态定长的文件转换成静态的 Playlist 文件和 Segment 文件就一劳永逸了,Elixir TV 直播台则需要针对每个频道维护一个实时的内容队列。

Scheduler 使用 Exilir 中的 GenServer 进行状态管理,通过定时更新滑动窗口中的视频 Segments 及对应的描述信息,提供了获取即时 Playlist 文件的能力,简单干净、利落高效地实现了 Elixir TV 开台所需的功能。

HLS Server

HLS Server 提供了三个 HTTP 接口为客户端调用,分别是:

- GET /playlist.m3u8 => static master playlist

- GET /:variant/playlist.m3u8 => live variant playlist

- GET /:variant/:video_id/:media_segment_name.ts => serves video files from local file system

前两个接口用于获取 Playlist 文件,客户端基于 Master Playlist 中的信息初始化播放器,基于 Variant Playlist 中的信息获取 Media Segment 资源的地址。由于是直播,客户端需要定时更新这些信息。第三个端口则是供客户端获取具体的视频文件,用于播放使用。

Conclusion

有了上面这些模块,Elixir TV 初具雏形。

接着,Horvo 和大家分享了真实世界的大型直播产品架构,指出了 Elixir TV 的一些不足之处。

Videos Should be Encrypted

真实宇宙在大刘的描述里是充满恶意的黑暗森林,大家需要伪装和噤声来保护自己。作为视频平台 —— Elixir TV 也一样需要考虑保护自己的核心内容,即视频文件。

Horvo 介绍了三种不同的保护策略:

- 视频片段文件可以通过 AES-128 算法进行加密,保障传输安全

- 上述对称加密密钥的获取接口需要对访问者的身份进行鉴权,确保视频解密发起来自合法客户端

- 更高级的内容保护,如 DRM 等技术,可以保证视频文件不能在不同设备间进行拷贝和转移。

Monetary Should be Addressed

真实世界在达尔文的描述里是物竞天择、适者生存的。Elixir TV 也需要从第一天就开始考虑变现的问题。参考 Tubi 使用免费视频 + 广告的模式来构建营收的模式,Elixir TV 需要构建 Ad Insertion Service 作为用户访问节目列表的门面,在合适的时间段,向广告平台发起竞价邀约,并选择对本平台更有利的广告单进行成交,在返回给用户的视频播放描述文件中插入这样的视频片段以赚取营收。

Horvo 还同时介绍了在服务端做广告插入的优势。广告视频文件和普通的视频片段一样,在服务端的 Ad Insertion Serivice 被插入了视频播放 Playlist 文件,因此失去了广告特征,可以避免被一些浏览器的广告屏蔽插件屏蔽,从而保障平台和广告客户的权益。

精彩互动

Ad Insertion Service 如何实现针对每个用户的个性化广告插入?

Horvo:Server Side Ad Insertion(SSAI)服务会为每一位用户的 Playback Session 维护一个单独的 Media Playlist,直播场景中的 Media Playlist 会随着时间滚动刷新,当 Playlist 中出现 Ad-break 信息时,SSAI 会向 Ad Server 发起一次广告请求,这一广告请求会携带用户的一些特征信息以便 Ad Server 针对该用户进行个性化的推荐。在 HLS 流中进行广告插入也有一种行业规范 (SCTE-35),HLS 内容的生产商需要使用行业规范的 Tag 将广告位置标注出来。

Ad(广告)是否会被客户端篡改?

Horvo:我们做 SSAI 的主要目的是防止客户端的屏蔽或篡改,这一部分的实现是由 SSAI 服务在完成广告获取后将原有携带 Ad-break 信息的 Media Playlist 过滤为没有 Ad-break 信息的 Playlist,而原先在 Ad-break 区间中的 Media Segment 会被替换为真实的 Ad Segment。客户端无法通过检测 Ad-break Marker 来监测广告位置,因而也就不会发生篡改。

而如果我们不用 SSAI 服务,而是在客户端进行广告请求和广告插入,客户端便可以识别到 M3U8 文件中的 Ad-break,这种情况下,客户端比较容易对广告进行篡改或屏蔽。

M3U8 这一文件在哪一个部分生成?Scheduler 的意义是什么?

我们在 Transcoder 之后会得到一个 HLS 的输出格式,这一 HLS 只是对某一视频可点播的形式。在 Scheduler 进行编排之后的 HLS 输出才是真正的直播形式的内容。

为什么使用 Elixir?

关于 Tubi 和 Elixir 的故事,可以参考 Tubi VP of Engineering 陈天分享的当时的故事 —— 为什么使用 Elixir?多位工程师讲述背后的故事

Horvo 基于自身使用 Elixir 开发的五年经验,在 Elixir 开发体验和 Elixir 在生产环境中的表现做了简单的分享:“我之前做 Ruby on Rails 开发,Ruby 非常重视开发者的开发体验,强调 Developer Happiness。而 Elixir 和 Ruby 之间有很多渊源,比如 Elixir 创始人 Jose Valim曾是 Ruby 核心开发者之一,因此 Elixir 在开发者体验上也与 Ruby 有极其相似之处,非常友好。

另外,在现实的生产环境中,Elixir 在 Web Server 需要面对高并发量的请求处理的情况时,表现也是非常不错的”。

Elixir 在 Tubi 的其他应用案例

使用 Elixir/OTP 构建多媒体 E2E 处理平台

Ruby 思想在 Elixir 项目中的应用

一个潜藏在 Elixir 代码库里 7 年的性能问题

加入 Tubi 一起成长变强!

热招岗位:https://tubi.tech/careers/

微信公众号:【活动回顾】用 Elixir 开发 HLS 直播后端服务

猜你喜欢

转载自blog.csdn.net/weixin_49193714/article/details/131575841
HLS