使用Mux,Stream和Flutter进行实时流式传输

从Twitch之类的流行游戏网站到Instagram之类的日常休闲apps,现在,实时流媒体无处不在。Apps使用实时流媒体和实时视频来连接用户,为其平台增加了另一层次的交互性。

如果考虑使用现代实时流,在构建应用程序时你还需要考虑许多细节。比如,大多数流行的流媒体平台除实时视频外还包括实时聊天。对于开发人员而言,这会增加时间和成本方面的开销。

本文将简要介绍支持实时视频并在Flutter中构建小型流应用程序的技术。

如果你赶时间,请随时跳到“实践中的流媒体”部分。这是背景TL; DR:

实时流媒体非常复杂 ,其中 会涉及许多不同的运动部件, 因此需要 正确操作。在开始编写代码之前,我们必须了解一些实时流功能背后的高级概念。原始视频在到达你的计算机之前就已被转换、压缩和转码。

实时流式传输的历史可以追溯到20世纪90年代末和21世纪初,用于实时流传输的协议。实时消息协议 / RTMP是由 Macromedia 开发的,该公司后来被Adobe于2005年底收购。

RTMP协议是专有协议,旨在早期通过Internet在Flash服务器和多个Flash客户端之间流式传输视频和音频数据。早期的RTMP版本具有低延迟,通常从服务器到客户端有3-5秒的延迟。

随着岁月的流逝,Flash的统治地位开始动摇,移动、智能电视等新设备开始流行。最终,Adobe决定实施RTMP协议,这赋予了它新的活力。

它在网络浏览器中的普遍存在使它成为流服务器的严格标准,但是随着HTTPS Live Streaming(HLS)等新的前端协议的兴起,RTMP在客户端的流行度开始下降。

如果你想了解更多有关RTMP的信息,可以在Adobe网站的以下URL上找到完整的规范:

实时消息协议 (RTMP)规范

实时消息协议 (RTMP)规范)
实时消息协议 (RTMP)规范www.adobe.com

这是RTMP的摘要,该协议位于互联网的传输控制协议(俗称TCP)之上。默认情况下,它使用端口1935进行通信。随着时间的流逝,对该协议的更新增加了传输层安全性(TLS)支持(RTMPS)和由Adobe开发的专有加密形式(RTMPE)。

如今,RTMP不再像以前那样占主导地位,但仍被流媒体服务器使用,并在实时流媒体周期开始时从源中提取原始视频。但是,对流进行编码、压缩和重新打包,可以更好地适应终端设备。

基本流媒体管道:bug:

0_xD5dCaElGGPOLj7c

管道步骤

在欣赏自己爱看的电视节目的最新版本或自己喜欢的体育节目时,原始视频必须经过几个步骤,才能到达你的设备。

首先,从摄像机或数字录像机捕获原始视频。原始输入可能非常庞大,不适合通过Internet传输。为了减小内容的大小并使其更易于访问,将其编码并压缩为开放编解码器,例如H.264,VP8。这可以根据用户的需求而变化,但H.264是视频编码的首选。

接下来,使用流协议将编码的视频分发到媒体服务器。现在,最受欢迎的流协议是RTMP,也可以使用其他协议,如MPEG-DASH或安全可靠传输(SRT)。

然后,将由这些协议创建的流发送到媒体服务器,在此将其进行代码转换、调整大小、并拆分为不同的分辨率和格式,以交付给最终用户。在大多数情况下,流会重新打包为各种形式的质量和比特率,以更好地为其他互联网连接的用户提供服务,此过程称为“ transmuxing”。

最后,使用诸如MPEG-DASH或Apple的HLS之类的方法将流发送给最终用户,这是两种最广泛使用和最兼容的实时流传输方法。通过内容交付网络或CDN分发流以减少等待时间和流服务器负载的情况并不少见。

实践流

如果你还看不出来,构建一个端到端的流媒体平台绝非易事。除了创建和维护端到端管道所涉及的技术复杂性之外,开发和扩展管道以及在不同区域维护服务器以实现低延迟播放的成本和时间也增加了。

幸运的是,某些公司和服务擅长于此。Mux等流媒体平台使开发人员和企业可以将实时视频集成到他们的应用程序中,同时减少其上市时间和传统上与开发实时视频相关的技术经济障碍。

在开始之前,让我们概述一下我们的应用程序的一些目标:

  • 播放自定义HLS和RTMP流
  • 显示过去流的按需存档
  • 视频下的实时消息传递和聊天

项目设置:package:

我们将使用MuxStream处理视频流和实时消息传递,可以在这两种服务上创建免费帐户来获取API密钥。如果是Mux,输入电子邮件后,按照发送至收件箱的说明进行操作。

0_IrhH5KfG4giUl-A4

Stream的过程与此类似:选择用户名,然后输入你的电子邮件和密码。

0_y39g3NEu7MfvT1UM

接下来,我们可以在Mux上创建实时测试流,以验证一切运行正常。导航到屏幕左侧的侧菜单,然后在视频选项下选择“实时流”子类别。

在这里,可以直接从仪表板查看正在进行的流或创建新的流。对于我们的测试,选择右上角的“创建新的实时流”。

0_18hIRyoIPcIl9OwL

现在为我们提供了一个控制台,该控制台可以创建新的实时流。由于我们使用的是免费帐户,会有一条警告我们信息流将被限制5分钟的消息。但是,此限制仅适用于视频的长度,并不限制对其他功能的访问。流结束后,我们可以对实时流的各个方面进行自定义,例如流和资产的隐私设置。你还可以为流设置许多选项和配置,要了解有关不同选项的更多信息,我强烈建议你查看Mux文档上的入门指南

0_Vbuj-zW8FI-blCHO

运行请求后,你将看到类似于下图的响应。对我们而言,最值得注意的键是 stream_keyplayback_ids.id ,这两项将稍后分别用于发布和查看我们的流。

0_vQApURnsyqyHLSlt

:memo:注意:切勿发布流密钥,此值应始终设为私密。

最后,可以通过单击侧面菜单中的实时流选项或底部的“查看实时流”选项,来查看新创建的流的详细信息。

0_ThfgNZyOymcYN95O

此页面包含有关当前流的信息。在目前情况下,由于我们没在直播,因此它将流显示为“空闲”。我们还可以从实时流概述中看到唯一的实时流ID,侧面的缩略图预览以及流的回放ID。

为了快速测试我们的视频流,我们可以使用Larix之类的直播app从我们的移动设备进行广播。

Google Play上的Larix:

Larix Broadcaster - Google Play上的Apps

Larix Broadcaster允许通过 WiFi实时从你的移动设备流式传输视频或音频…
play.google.com

苹果App Store中的Larix:

‎Larix Broadcaster

‎Larix Broadcaster Larix Broadcaster允许通过 WiFi实时从你的移动设备流式传输视频或音频…
apps.apple.com

在Larix中,我们可以使用URL创建一个新的连接 rtmps://global- live.mux.com:443/app/<YOUR-STREAM-KEY> 。我还使用我的Mux凭证使用RTMP授权;但是,此步骤不是必要的。

保存连接后,我们可以点击Larix上的红色“记录”按钮开始直播。

%E6%9C%AA%E5%91%BD%E5%90%8D_%E5%89%AF%E6%9C%AC

要验证流是否正常运行,请尝试刷新实时流预览页面或访问URL https://stream.mux.com/YOUR-PLAYBACK-ID.m3u8

恭喜:tada:,你已成功迈出了构建实时视频应用程序的第一步。接下来是构建应用程序的框架!

构建APP布局:man_artist:

首先创建一个新的Flutter项目并命名。创建完成后,将以下内容添加到你的 pubspec.yaml

0_LVT3PrCgE7s9enqc

简单起见,我们app将具有三个屏幕。第一个屏幕将是所有用户启动应用程序时看到的登录页面。在这里,用户可以输入自定义URL和昵称来与朋友一起观看实时视频,也可以直接转到app的主页以查看当前和过去的实时流列表。

对于视频播放屏幕,我们将屏幕分为两部分,顶部是视频播放器,底部是实时聊天。

编码登录页面:flight_arrival:

0_BQHAMGm1jhRaVjor

我们的目标网页布局由一些小部件组成,一个 Column 用于设计两个 TextField s的小部件,一个 Icon ,和一个用于执行导航的操作按钮。如果用户输入自定义URL,我们会将按钮从矩形 ElevatedButton 更改 为带有图标的圆形按钮。

该页面的代码将类似于以下内容:



:bulb:你知道可以使用ShaderMaskover小部件来应用渐变吗?请注意,在上面的代码中,我们使用ShaderMask在目标网页图标上应用渐变。

接下来,我们可以继续创建主页的布局。

主页布局

0_3Hd841r0N-2p65tk

主页设置有点复杂。为了易于管理,我选择使用两个单独的小部件。

第一个窗口小部件包含一个静态方法,用于简化页面控制器的导航和初始化。稍后,我们将集成 cubit 用来处理状态更改。

我们的主页的实际内容将包含 CustomScrollViewPageViewSliverGrid 。页面视图显示当前流的列表,而过去的实时流则显示在条形网格中。为了区分不同的部分,我们可以使用带有大标题的 CupertinoSliverNavigationBar



最后,可以使用简单的 AspectRatio 卡片来实现小部件 FeaturedStreamCard 。在 AspectRatio 缩放和调整窗口小部件时, AspectRatio 对于保持图像比例非常有用。

image

综合所有内容,我们可以在上一个屏幕中配置导航器 LandingPage ,通过实现 onContinueToHomePressed 功能将其导航到新屏幕。

uture<void> onContinueToHomePressed() async {
  if (formKey.currentState.validate()) {
    Navigator.of(context).pushReplacement(HomePage.route());
  }
  return;
}

视频页面布局:video_camera:

0_3Hd841r0N-2p65tk

到目前为止,我们应用程序中的最后一个屏幕是最重要的。毕竟对于实时流媒体app没有视频播放器和聊天功能的有什么好处?:stuck_out_tongue_closed_eyes:

播放器的设计包含两个不同的元素:播放器本身和底部的聊天列表。现在,让我们专注于播放器。如果你还记得,我们最初在项目中添加了一些软件包,其中之一是视频播放器插件 yoyo_player 。我选择此程序包是因为它具有开箱即用的友好UI并支持HLS / RTMP流。但是,你也可以根据需要使用官方 video_player 软件包。


image
可能会说,我们将使用一个 Column 和两个 Expanded 来创建布局。目前,我仅创建了视频播放器,稍后我们将讨论如何聊天。

后端设置:hammer_and_wrench:

像所有应用程序一样,我们需要为app创建一个后端。在案例中,后端指的是负责与外部服务进行通信的应用程序层。由于在本教程中使用的是MuxStream,因此我们将创建一个简单的后端,该后端实现应用程序所需的功能。

首先,让我们配置Mux后端。实现此后端所需的代码最少,因为只有两个函数要实现: fetchPastLivestreamsfetchLivestreams 。这两个函数都将返回对象列表,我们可以通过创建简单模型将其转换为对象。

:bulb:注意,我们正在将Mux API字符串传递给类。这是一个非常简单的api,它向mux查询活动的和过去的实时流。你可以在此处找到示例api 。比较好的做法是,你可以在运行时使用config文件中的Dart Define将这些值传递给你的应用。

类:

模型:

:bulb:Mux会为我们的视频生成缩略图!我们可以通过将播放ID与它们的图像URL串联来访问这些缩略图。

接下来,是时候配置Stream来处理我们的聊天了。

流概述:bulb:

Stream提供了一种易于集成的聊天平台和多种语言的客户端SDK。Stream的目标是帮助用户以最少的设置和开销将高性能、低延迟的聊天无缝集成到他们的app中。

在我们的情况下,Stream已经作为预定义类型开箱支持实时流。你可以转到我们之前创建的项目的Stream仪表板,以查看和自定义这些设置。

:zap:getstream.io >项目>聊天>概述>频道类型

0_9qtPIxUYcGCwP3Q2

实施流后端:hammer_and_wrench:

完成Stream后端与实现Mux后端非常相似。在这种情况下,我们具有生成令牌以及配置用户和通道的三个功能。由于不熟悉某些Stream术语,因此可以将频道视为包含给定对话的所有消息的框。频道通常有一种类型(在示例中为“直播”)和唯一的ID。

你可能会注意到,在下面的示例中创建的频道有从视频URL生成的ID。这样可以确保如果与朋友共享视频,那么他们都可以进入并参与同一频道。


image
根据个人喜好,我喜欢将我的不同服务/后端组合到一个名为 Backend 的类中。

在这里,我们可以创建用于创建类的初始化程序。

最后,可以在主要函数中初始化后端并将其传递给应用程序。

状态管理:gear:

最后,进入开发Flutter应用程序最令人兴奋的环节:选择状态管理模式。:smile:

我会让事情变得简单,并使用广受欢迎的 bloc 软件包来处理应用程序。具体地讲,我将使用 cubit ,因为我喜欢它的易用性和设置少。

通过检查应用程序的用例和功能,我们可以确定 cubit s的一些候选对象:

我不会详细介绍每个cubit的实现,但是总体流程类似于以下示例:

Cubit:
image

状态:

要查看每个块的实现,可以查看GitHub上的存储库:

Nash0x7E2/live-flutter

This repo contains code for my tutorial on adding live streaming video with Mux and Stream Chat to a Flutter…
github.com

一旦实现了cubits,我们就可以继续使用 BlocProvider 进行注册以在应用程序中使用。

main.dart 中,我们删除默认的 MyApp 窗口小部件并创建一个新的 Stateless 窗口小部件。在此小部件中,我们将为应用程序创建物料app并注册我们的块提供商。

为了方便起见,可以创建一个 MultiBlocProvider 来注册所有四个cubit类。最后,可以在 StreamChat 中包装 MaterialApp ,并将之前创建的Stream客户端作为必需参数传递。

:bulb:你知道可以使用Dart的级联表示法创建一个 cubit

后立即触发功能吗?我们使用这种格式来加载初始的实时视频和存档视频。

合并:zap:

你表现得很好!实时流拼图的最后一部分是使用来自我们创建的cubit和后端的实时数据替换应用程序中的静态内容。

让我们从最简单的部分开始,更新登录页面。可以在导航到主页之前修改 onPress 功能以配置用户和频道。

image

注意,在配置用户时,我们正在 onCustomUrlGoPressed 中使用await 。这是因为Stream SDK要求在配置频道之前必须具有活动的WebSocket连接。

接下来,可以通过替换 build 内容来更新 HomePage

image

在这里,我们通过显示状态加载时以及 Text 错误发生时的加载器来处理一些用例。

现在,可以继续 _HomePageContent 实施实时流和存档文件。




image

最后,我们可以使用实例 StreamChannel 替换视频播放器页面中的临时容器。这是Stream SDK提供给我们的小部件,可以显示消息列表。流通道需要两个参数,一个通道和一个子通道。流通道的子级用于显示通道中的消息。


image

完成了!运行应用程序,并使用Larix app开始直播!

恭喜

上传中:0_vglhRBB6_b5LGev5.png…
哇!从了解实时流的内部工作原理到使用Flutter构建简单的应用程序,我们在本文中介绍了很多内容:iphone:

这只是冰山一角。如果您想了解更多,并尝试建立自己的项目,该代码可以在我的Github上发现在这里

请务必查看MuxStream,以了解有关视频流和聊天的更多信息。两种服务都提供免费试用。我希望你能检查它们并尝试创建自己的Live Flutter应用程序。

感谢阅读!

原文作者 Nash
原文链接 https://medium.com/flutter-community/live-streaming-with-mux-stream-and-flutter-2c03d581b1b

推荐阅读
作者信息
AgoraTechnicalTeam
TA 暂未填写个人简介
文章
149
相关专栏
本专栏仅用于分享音视频相关的技术文章,与其他开发者和 Agora 研发团队交流、分享行业前沿技术、资讯。发帖前,请参考「社区发帖指南」,方便您更好的展示所发表的文章和内容。