Flutter 在音视频研发中的不断探索
Flutter 简述
Flutter 是一个跨平台框架,以往的做法是将音频、视频和网络这些模块都下沉到 C++ 层或者 ARM 层,在其上封装成一个音视频的 SDK ,供 UI 层的 PC 、 iOS 和 Android 调用。
而 Flutter 做为一个 UI 层的跨平台框架,顾名思义就是在 UI 层也实现了一个跨平台开发。可以预想的是未Flutter发展的好的话,会逐渐变为一个从底层到 UI 层的一个全链路的跨平台开发,技术人员分别负责 SDK 和 UI 层的开发。
Flutter 开发的优点有哪些
我们可以看一下,为什么 Flutter 可以实现高性能:
原生的native组件渲染以 IOS 为例,苹果的UIKit通过调用平台自己的绘制框架 QuaztCore 来实现 UI 的绘制,图形绘制也是调用底层的 API ,比如 OpenGL 、 Metal 等。
而 Flutter 也是和原生 API 逻辑一致,也是通过调用底层的绘制框架层 SKIA 实现 UI 层。这样相当于 Flutter 他自己实现了一套 UI 框架,提供了一种性能超越原生 API 的跨平台可能性。
我们说一个框架最终性能怎样,其实取决于设计者和开发者。至于现在到底是一个什么状况:
在闲鱼的实践中,我们发现在正常的开发没有特意的去优化 UI 代码的情况下,在一些低端机上,Flutter界面的流畅性是比Native界面要好的。
Flutter 音视频设计理念
为什么要使用 Flutter 进行音视频开发
随着Flutter
在越来越多大厂的业务落地,大家不难发现,音视频是一块绕不开的业务。短视频、IM、新媒体等相对较重的业务中都会有音视频的身影,那么如何通过一个强大的跨平台框架去实现一个强大、高性能、可控的音视频播放功能呢?我们是否还仅仅停留在使用插件的上层API
?相信能耐心看完本文会,你对Flutter
上的音视频实现会比之前有更深入的理解
Flutter 开发音视频的实现思路
开始之前,大家可以先思考一下如果是你来做一个Flutter
的视频播放器,你会如何去实现?你会遇到哪些困难呢?带着问题来看文章往往会更有收获。可能很大一部分同学都会和我一样首先跳出来一个词 —— PlatformView
。确实,PlatformView
看起来是个不错的方案,PlatformView
作为一个在Flutter 1.0
即发布的技术方案,算是比较成熟且上手较快的方案。但很显然,今天我们的主角不是它,为什么不是这个可爱的方案呢?请大家思考这样一个业务场景:
比如我们想调用摄像头来拍照或录视频,但在拍照和录视频的过程中我们需要将预览画面显示到我们的Flutter UI
中,如果我们要用Flutter
定义的消息通道机制来实现这个功能,就需要将摄像头采集的每一帧图片都要从原生传递到Flutter
中,这样做代价将会非常大,因为将图像或视频数据通过消息通道实时传输必然会引起内存和CPU
的巨大消耗!—— Flutter中文网
也正是因为有这个业务场景,可能我们今天的主角就要登场了——Texture
(外接纹理),会不会有很大一部分好兄弟一脸懵逼?
简单的介绍一下:Texture
可以理解为GPU
内保存将要绘制的图像数据的一个对象,Flutter engine
会将Texture
的数据在内存中直接进行映射(而无需在原生和Flutter
之间再进行数据传递),Flutter
会给每一个Texture
分配一个id
,同时Flutter
中提供了一个Texture
组件。
const Texture({ Key key, @required this.textureId, })
video_player
video_player
是Flutter
官方plugin
中的音视频播放插件,我们不妨以这个插件为例,细看其中的一些端倪。我会通过几部分的个人认为比较关键的源码,给各位点出该插件的实现方案。
FLTVideoPlayer
首先我们可以看到源码中封装了一个叫FLTVideoPlayer
的类
如果仅仅是PlatformView
的简单展示,此处无需自己封装如此复杂的一个Player
类,我对类中的方法和参数都做了注解,为了大家都能看懂,我给每一行都扣了注释。
注意,其实这个所谓的FLTVideoPlayer
的核心点并不是那个看似亮眼的play
方法,这里我要给大家介绍的是上面用虚线标出的初始化方法。看源码就可以发现,无论是加载本地A sset
音频,或是url
的音频,都调用了该方法。
FLTVideoPlayerPlugin
那我们如何将Native
层的数据传输到Dart
层呢?这就是我们插件要实现的部分。这部分直接贴出核心部分的代码吧。大家可以看到这里,我们选用的PlatformChannel
是EventChannel
, 这个地方为什么不是methodChannel
或者说BasicMessageChannel
,其实答案已经在我们的上文当中了,我们需要将我们获取到的视频数据进行传输,更贴切的是一个流式的传输,而EventChannel
就是为了数据流而生的。
再来仔细看看这个方法吧,方法中很显然,我们创建我们的EventChannel
,并没有和以往简单插件一样用固定的channelName
,此处我们的channel
和我们的textureId
相关。为什么这么设计呢?其实是为了我们的多窗口播放功能,也就是在插件的example
展示的一个界面中多个播放画面的效果,其实这一类的设计还可以应用在视频通话实现中的多窗口会话,说白了就是可以在Flutter
中对应多个不同的Widget
。
Flutter Source Code
有关Dart
方面的具体实现策略也是主要通过EventChannel
实现的,在EventChannel
中会加入插件中支持的feature
,包括暂停,轮播等。
我们首先找到了我们的EventChannel
定义处。看起来一切正常,唯一最大的疑问是,textureId
是怎么拿到的呢?是如何去和原生建立连接的呢?咱们继续往上找该方法的调用在一个MethodChannelVideoPlayer
类的方法中调用,但还是看不出来textureId
的来源。
OK,那就继续找,继续找此处videoEventsFor
的调用点,但还是看不出来!仅仅看出来传入了一个私有变量,很巧合的也叫textureId
.
点击跳转到create
方法的实现,我们在这里初始化VideoPlayer
,同时返回他的textureId
。
终于,我们到达尽头,尽头是一个BasicMessageChannel
,我们在这里通过BasicMessageChannel
在Flutter
和Native
层进行通信,在其中回调我们的textureId
。
总结
本文主要给各位介绍了 Flutter 中实现音视频的一种方案,外接纹理(Texture
),这也是Flutter
官方视频插件所采用的方案。应该也颠覆了各位以往对Flutter
插件的一些理解。那么我们在选择实现方案时是选择PlatformView
还是Texture
呢?
转载自:https://juejin.cn/post/6988002903701061646