大橙子网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
英语的学习很重要,如何轻松学好英语?如何快速记忆英语单词呢?下面是由我给大家带来关于快速记单词的方法,希望对大家有帮助!
成都创新互联公司是一家朝气蓬勃的网站建设公司。公司专注于为企业提供信息化建设解决方案。从事网站开发,网站制作,网站设计,网站模板,微信公众号开发,软件开发,微信小程序开发,十余年建站对成都OPP胶袋等多个方面,拥有丰富建站经验。
快速记单词的方法
1、单词卡片——最直接的单词操练教具
英语教学遵循先听说,后读写的教学原则。图片是培养小孩子的听说能力,帮助小孩子建立单词的音和义之间的联系;而单词卡片则是培养小孩子的单词认读能力,帮助小孩子建立单词的音、形之间的联系。认读单词是单词教学的终极目标。大声说,小声说,与学生唱反调。就是老师说一个单词,用的声音量不同,一个大声,一个小声,学生要做出相反的,例如老师两次朗读cat,一次是大声,一次是小声,则学生跟着老师说,正确的是先小声,后大声,如果学生像老师一样先大声再小声就错了。 设陷阱,让学生跟读卡片上的单词,老师故意经常读错,读对的学生可以跟读,读错的就要求学生马上做出反映,双手叉腰,瞪着眼睛,做出生气的样子,但不准发出任何声音。 反映错误的淘汰,也可采取小组记分! 踩地雷,选定一个单词为地雷,老师领读很多个单词,读到该单词的时候,有谁跟着读了,就是中地雷了,其他学生就一起指着他说:one, two, three, bomb。
2、图片——使用最频繁的单词操练教具
图片可以用于每一节单词教学课,不仅适用于单词呈现,也适用于单词操练、巩固环节。在课堂上,经常会采用“What’s the next?”、“What’s missing?” 这两个猜一猜的游戏。操作方便,而且面很广。“What’s the next?”:先让小朋友快速看图说单词,然后不打乱顺序,从第一张单词图片开始,让小朋友猜一猜它后面的是什么。“What’s missing?”:从单词图片中随意抽掉一张,让小朋友猜一猜少了哪张。小孩子最喜欢竞争性的游戏,在猜一猜的游戏中,孩子们显得特别兴奋,经常可以听到孩子们“Yeah”的欢呼声。 对于稍长的单词,可以采用Hide and seek游戏:如French fries, 把这一图片藏在某一个小朋友的位置上,让小朋友来找,其余学生一起大喊French fries,如果据目标越来越近,则喊得声音越来越大,反之,则越轻。这一方法对稍长的单词很有效的。
3、动画——有趣的单词操练媒体
动画课件集声音、色彩、动画于一体,绘声绘色,生动逼真,有利于调动学生的学习积极性和主动性,激发并保持学生学习英语的兴趣,使他们敢于说,乐于说,从而促进学生语言表达能力的提高和发展。如教学颜色时,我利用色彩大转盘,让学生用I like…说一说自己喜欢的颜色,再转动转盘,比一比谁是幸运儿;又如在操练食物单词时,我利用Flash可以逐步呈现和快速呈现的特点,让学生在有限的时间里猜出单词。
英语的学习方法
1、课前预习
预习可以使我们有心理准备,可以帮助我们提高课堂效率。提前预习第二天内容,可以充分了解自己的难点在何处,听课时就能够有的放矢。
2 、课堂听讲
一般在课堂节奏是一节课的45分钟,前5分钟复习,中间25---30分钟讲解练习,后10分钟综合训练及小结。在课堂上我们应该做到以下几点:
(1)认真听,多动笔。
上课全神贯注,认真听讲,做好笔记,无论听、说、读、写都要使自己始终活跃。我们应该记录什么呢?首先是老师讲解时的重点句子,其次要记下老师板书的重要内容,最后要记下这节课自己不懂的地方或者自己的一些所感所得。我们可以将这些记录在课本上。
(2)积极参与。
英语是实践性强的学科,要大胆地练习,敢说、敢读,积极回答老师提出的问题。
(3)松弛有度。
我们的精力有限,不可能整节课都全神贯注。在我们掌握很好的环节,在老师调节课堂气氛说点笑话时,在进行小组活动的时候,都是我们稍微放松的好时机。
3 、课后学习
(1)自习课的时候,老师要给大家做每日一练,也就是出几个题目,练习当天所学内容。同学们要独立完成,有不会的题目及时解决。
(2)回家后,先复习当天所学知识,再写家庭作业,最后预习明天要学习的内容。
(3)有时间就听课文录音。吃饭时,睡觉前,都是播放录音的时间。即使随便听也无所谓,我们需要的是创造尽可能多的英语氛围。
(4)学习其他英语教材,作为课本的补充和完善。我们可以学到地道的英语,读到妙趣横生的小故事,可以拓展我们的视野。
最容易记忆的三类英语单词
一、象声词
象声词又称拟声词,是模拟各种声音的词。它包括三类,即模拟物体发出的声音、模拟人发出的声音和模拟动物发出的声音。有的象声词与它所模拟的声音非常相似,这样的词很容易记忆;有的象声词与它所模拟的声音不完全相似(部分相似),但我们只要加以联想,也容易记忆。而如果我们不知道一个象声词的来源(不知道它所模拟的声音),这个词就很难理解和记忆。例如:scud(飞毛腿、速跑)一词就不易理解和记忆,但如果知道它是模拟“喀得喀得”的速跑声,就很容易记住。
1.模拟物体发出的声音,如:
bang一砰然作响,猛撞[拟“梆梆”撞击声]
bubble一冒泡,沸腾[拟水冒泡声]
creak一咯吱咯吱作响[拟物体摩擦声]
flutter一振翼,颤动[拟反复拍动声]
gong一锣[拟“哐哐”的锣声]
hack一砍,劈[拟“啪啪”的砍、劈声]
iiggle一轻轻跳动[拟跳动声]
kodak一小型照相机拍摄[拟摄影时照相机发出的“咔嗒”声]
plonk一物体落下碰到另一物体表面时的扑通声[拟“扑通”声]
rustle一发沙沙声[拟树叶、纸张等摩擦时发时的“沙沙”声]
sizzle一咝咝声[拟油炸食物或水滴接触热铁时的“咝咝”声]
toot一(拟喇叭、号角、笛等的)嘟嘟声,吹喇叭
whir(r)一呼呼声[拟物体移动、转动或飞行时的“呼呼”声]
2.模拟人发出的声音。如:
babble一牙牙学语声[拟婴孩学话“吧吧”声]
cackle一咯咯地笑[拟“咯咯”笑声]
groan一呻吟,哼声[拟痛苦的呻吟声]
hiccup一打嗝儿,打呃[拟打呃声]
iabber一急促而不清楚地说话[拟急促的说话声]
puff一吹气[拟吹气声]
riot一骚动,暴乱[拟狂闹声、嗷嗷叫声]
sip一呷饮,啜饮[拟吸吮声]
titter一窃笑,傻笑[拟“嘁嘁咯咯”的窃笑声]
whoop一哮喘声,高呼声[拟“呼呼”声]
yawp一大声叫嚷,嚎叫,喧闹[拟吆喝声、叫嚷声]
3.模拟动物发出的声音。如:
caw一呱呱地叫[拟乌鸦叫声]
coo一咕咕地叫[拟鸽子“咕咕”叫声]
growl一嗥叫,怒吠[拟狗的低吠声]
hoot一猫头鹰叫声[拟猫头鹰“呼呼”叫声]
mew一咪,喵[拟“喵喵”猫叫声]
neigh一马嘶[拟马嘶声]
quack—嘎嘎地叫,呱呱地叫[拟鸭子叫声]
roar一(狮、虎等)吼叫,咆哮[拟野兽吼声]
yowl一嚎叫,长吼[拟狗、野猫等嚎叫声]
二、与中文读音相似、近似的单词
这类单词共有三种:
1.由英文译成中文的,如:sofa(沙发)、hysteria(歇斯底里)、humor(幽默)、ampere(安培)、brandy(白兰地)、cartoon(卡通)、shampoo(香波)、trust(托拉斯)、poker(扑克牌)、salad(色拉)、tango(探戈)、pudding(布丁)、shock(休克)、heroin(海洛因)
2.由中文译成英文的,如:typhoon(台风)、kowtow(叩头)、oolong(乌龙茶)、litchi(荔枝)、ginseng(人参)、longan(龙眼)等。
3.既非英译中,亦非中译英,而是中文、英文读音巧合,如:tow(拖)、loot(掳)、bandage(绷带)、fee(费)、tun(桶)等。
三、与另一单词有联系的单词
对一个普通的英语学习者来说,graze(牛羊吃草)一词也许是个陌生的单词,但若告诉他这个单词来自熟词grass(草),他会马上感到这个单词不太陌生了,似乎是个“半熟脸”,也就很容易记住了。类似这种情况的陌生单词在英语里为数不少。每一个这样的生词都有一个与它有内在联系的熟词。它们的形、音、义都很相近,只要我们对照比较,便可马上“变生为熟”,不易忘记。
如:dusk[联系单词:dust(灰尘、尘土),原义是“尘土色的”,引申为“昏暗的、微暗的”→黄昏];interval[inter-(在……之间),val=wall(v—W)墙;“在两墙之间的空隙”引申为“在两种事物之问的空隙”→(空间或时间的)间隔、间隙];simpleton[对照simple简单的,引申为“头脑简单的人”→傻子、愚蠢者];resemble[re.加强意义,sem来自same同样的、相同的,引申为“差不多”→像、类似、相似]
猜你喜欢:
1. 背单词的十大记忆法口诀
2. 最强的单词记忆法--五步背单词
3. 世界记忆大师教你记英语单词
4. 记忆英语单词的15种方法推荐
5. 巧记英语单词的8种方法推荐
6. 最快记单词的方法
nan_scan 是一款支持iOS和android 的扫码器插件,支持用户自定义页面
1、配置:
android配置:在AndroidManifest.xml 下添加相机权限 uses-permission android:name="android.permission.CAMERA" /
iOS:在打开xcode,在info.plist 下添加 Privacy - Camera Usage Description ,打开相机权限
2、使用:
引入插件:在pubspec.yaml 中,
dependencies:
nan_scan: 版本号
使用案例方法:
或者:
demo效果图:
不久前,谷歌正式推出 Jetpack Compose 1.0 版本。近日,JetBrains 在此基础上发布了 Compose Multiplatform Alpha 版本,旨在将 Compose 扩展到桌面和 Web 端。
Compose Multiplatform 由 Compose for Desktop 和 Compose for Web 组成,通过 Kotlin Multiplatform 支持许多不同的平台。其中,Compose Desktop 采用 Google 的 Skia 图形库,来实现在 Windows、macOS 和 Linux 上的 UI 绘制,借此在所有支持的操作系统中提供统一的体验,类似于 Flutter 的做法。
根据 Kotlin 团队的说法,相比起 Electron 框架,Compose Multiplatform 在内存消耗、安装大小和 UI 渲染性能等方面将有更明显的优势。随着 Alpha 版本的发布,Compose Multiplatform 还收获了新的 Android Studio 插件,包括对在 IDE 中显示组件预览的支持以及许多附加功能。
我们希望通过本文帮助大家进一步了解 Compose 的跨平台能力,以及 JetBrains 将 Compose 从 Android 扩展到这些其他平台背后的主要驱动力是什么。
基于 Jetpack Compose 1.0
由谷歌打造的 Jetpack Compose 是一款用于在 Android 应用程序之内构建用户界面的官方框架,上周刚刚发布 1.0 版本。与此同时,Android Studio 代号“极狐”的首个稳定版 2020.3.1 也正式亮相。
尽管才刚迎来 1.0,但谷歌表示“目前 Play Store 中已经有超过 2000 款应用程序在使用 Compose——更重要的是,就连 Play Store 这款应用本身也在使用 Compose。”谷歌方面还表示,“我们一直在与一些顶级应用的开发人员进行合作,他们的反馈和支持帮助我们使 1.0 版本更加强大。”
Jetpack Compose for Android 迎来 1.0 版本
Compose 基于 Kotlin 开发,而 Kotlin 与 Android Studio(即官方指定的 Android IDE)均来自开发工具厂商 JetBrains。虽然 Jetpack Compose 专为 Android 打造(与谷歌的 Flutter 框架不同), 但 JetBrains 公司坚信 Compose 完全能够获得跨平台能力 。
Compose for Desktop: 这只是开始
Compose Multiplatform 可以说是该框架面向 MacOS、Linux、Windows 以及 Web 开设的一个端口,目前刚刚发布 1.0 Alpha 版本。虽然尚处于早期开发阶段,但 JetBrains 表示,其已经“为开发人员带来能够基本安全使用的稳定 API”。
TheRegister 就此事询问了 JetBrains 公司 Compose 项目负责人 Nikolay Igotti,希望了解为什么该公司在拥有了已经广泛应用于 IntelliJ IDEA IDE 及多种丰富变体的桌面应用程序跨平台 Java 框架之外,还要费力开发 Compose for Desktop。Igotti 的回答是,“旧有 Java 框架基本上就是修改版的 Swing。Swing 属于默认 JDK UI 框架,Swing 和 AWT(Abstract Windows Toolkit,抽象窗口工具包)。Compose 则完全是另一码事,当然我们也在设计中考虑到了互操作性需求……Swing 这套框架太陈旧了,最早出现在上世纪九十年代末。多年来人们对于 UI 的设计思路已经天翻地覆,Swing 显然满足不了要求了。”
JetBrains IDE 中的 Compose for Desktop 项目
Compose 与 Swing 有一个比较大的共同点:与其他使用本机控件的跨平台框架,比如例如 Java 的 SWT(Standard Widget Toolkit)以及微软的 Xamarin 有所不同,它们选择自主绘制控件。Compose 使用的 Skia 开源图形库,也在谷歌 Chrome、Flutter 及其他众多框架当中得到广泛应用。那这是否意味着 Compose 应用程序将没有自己的原生外观?对此,Igotti 的回应是,“这取决于开发人员的选择,取决于他们如何为应用程序设置主题。在这方面,Compose 的情况与 Flutter 等其他框架没什么区别。”
那 Compose for Desktop 应用程序是否依赖于 JVM(Java Virtual Machine)运行?Igotti 表示,“我们也知道,JVM 应用程序的发布情况可能比较棘手。因此我们提供自己的 Gradle 插件,其使用 jpackage 与 Jlink 以 JVM 应用程序为基础制作原生应用程序。Mac 的.dmg、Windows 的 MSI、Linux 的 deb 包等均可实现,大家用不着担心 JVM。”
也就是说,开发成果将会是一款被精心包裹起来的 JVM 应用程序。JetBrains 还有一款用于解决这个问题的 Kotlin/Native 编译器,“预计将在未来发布,或者专门用于桌面开发。”
对应用程序的另一种思考方式
那 Web 应用程序方面呢?Igotti 回应称,“我们使用 Kotlin/JS 编译器。”Compose 的 Web 版本不如桌面版先进,说明文档中也警告称“API 尚未最终确定,预计会发生重大变化。”此外,虽然 Web 版本确实使用 Compose 模型,但 API 却完全不同,而且会使用 HTML 与 CSS。所以,Web 版与 Compose for Desktop 之间能够共享的代码应该比较少。
据 Igotti 介绍,“Compose 代表着一种不同的应用程序思考方式。状态即 UI 的真实来源,而 UI 本身是无状态的,其表达永远由状态计算得出。在这方面,Compose for Web 采用一组相同的原语,完全相同的状态管理思路。但是对于具体的小部件集合与排列方式,Web 版与桌面版之间确实无法互通。”
说到这里,为什么要把 Compose for Android 扩展到多种其他平台之上?“Compose 的目标受众主要分为三类。首先是使用 Kotlin 与 Compose 的 Android 开发人员,他们希望把自己的开发成果交付至其他平台;其二是纯 Kotlin 开发人员,他们希望以‘一次编写、随处运行’的方式开发新的应用程序;第三则是那些不太熟悉 Kotlin 或者 Compose,但又希望开发出精美 UI 的用户,我们希望能为他们提供实现目标的工具。”
Igotti 并没有给出具体的发布日期,但表示自己希望 Beta 版能在今年秋天发布,“我们也希望能在今年之内推出 1.0 版本。”项目本身是完全开源的,“二十一世纪了,框架在大多数人们心目中就不应该收费。我们只是想开发一款长期缺失的软件”,补足 JetBrains 当前商业模式中的工具链。
那么,JetBrains 会在自己的其他工具中使用 Compose 吗?事实上,他们的 JetBrains Toolbox(用于管理已安装的 IDE)已经在使用 Compose,但 Igotti 表示短时间内 Compose 还无法取代 IntelliJ IDEA 等现有框架。“编辑器是其中最复杂也最重要的组件,经历了 20 年的发展演进,我们几乎不可能在中途进行重写了。无论是 JetBrains 还是我个人,都不打算强迫每个人都转而使用 Compose。我们的目标是为原有框架选项满足不了的用户提供新的解决方案。”
写在最后
那么,为什么除了 Flutter 之外,我们还需要另一个跨平台框架?虽然谷歌的 Flutter 最开始主要面向移动设备,但现在也开始向桌面及 iOS 进军,甚至比 Compose 还抢先了一步。不过,根据 StackOverflow 的最新调查, Flutter 使用的语言为 Dart;尽管 Dart 语言的人气正在增长(正是受到 Flutter 的推动),但仍然无法与 Kotlin 相提并论。
Compose 代表着一种独特的 UI 构建方法,也许最期待 Compose 跨平台功能的受众,正是那些曾在 Android 上使用过它、又特别喜欢这种 UI 构建体验的开发者。
想要进一步了解 Compose,国内 Android 开发者可访问以下链接查看中文手册:
延伸阅读:
文/陈炉军
整理/LiveVideoStack
大家好,我是阿里巴巴闲鱼事业部的陈炉军,本次分享的主题是Flutter浪潮下的音视频研发探索,主要内容是针对闲鱼APP在当下流行的跨平台框架Flutter的大规模实践,介绍其在音视频领域碰到的一些困难以及解决方案。
分享内容主要分为四个方面,首先会对Flutter有一个简单介绍以及选择Flutter作为跨平台框架的原因,其次会介绍Flutter中与音视频关系非常大的外接纹理概念,以及对它做出的一些优化。之后会对闲鱼在音视频实践过程中碰到的一些Flutter问题提出了一些解决方案——TPM音视频框架。最后是闲鱼Flutter多媒体开源组件的介绍。
Flutter
Flutter是一个跨平台框架,以往的做法是将音频、视频和网络这些模块都下沉到C++层或者ARM层,在其上封装成一个音视频的SDK,供UI层的PC、iOS和Android调用。
而Flutter做为一个UI层的跨平台框架,顾名思义就是在UI层也实现了一个跨平台开发。可以预想的是未Flutter发展的好的话,会逐渐变为一个从底层到UI层的一个全链路的跨平台开发,技术人员分别负责SDK和UI层的开发。
在Flutter之前已经有很多跨平台UI解决方案,那为什么选择Flutter呢?
我们主要考虑性能和跨平台的能力。
以往的跨平台方案比如Weex,ReactNative,Cordova等等因为架构的原因无法满足性能要求,尤其是在音视频这种性能要求几乎苛刻的场景。
而诸如Xamarin等,虽然性能可以和原生App一致,但是大部分逻辑还是需要分平台实现。
我们可以看一下,为什么Flutter可以实现高性能:
原生的native组件渲染以IOS为例,苹果的UIKit通过调用平台自己的绘制框架QuaztCore来实现UI的绘制,图形绘制也是调用底层的API,比如OpenGL、Metal等。
而Flutter也是和原生API逻辑一致,也是通过调用底层的绘制框架层SKIA实现UI层。这样相当于Flutter他自己实现了一套UI框架,提供了一种性能超越原生API的跨平台可能性。
但是我们说一个框架最终性能怎样,其实取决于设计者和开发者。至于现在到底是一个什么状况:
在闲鱼的实践中,我们发现在正常的开发没有特意的去优化UI代码的情况下,在一些低端机上,Flutter界面的流畅性是比Native界面要好的。
虽然现在闲鱼某些场景下会有卡顿闪退等情况,但是这是一个新事物发展过程中的必然问题,我们相信未来性能肯定不会成为限制Flutter发展的瓶颈的。
在闲鱼实践Flutter的过程中,混合栈和音视频是其中比较难解决的两个问题,混合栈是指一个APP在Flutter过程中不可能一口气将所有业务全部重写为Flutter,所以这是一个逐步迭代的过程,这期间原生native界面与Flutter界面共存的状态就称之为混合栈。闲鱼在混合栈上也有一些比较好的输出,例如FlutterBoost。
外接纹理
在讲音视频之前需要简要介绍一下外接纹理的概念,我们将它称之为是Flutter和Frame之间的桥梁。
Flutter渲染一帧屏幕数据首先要做的是,GPU发出的VC信号在Flutter的UI线程,通过AOT编译的机器码结合当前Dart Runtime,生成Layer Tree UI树,Layer Tree上每一个叶子节点都代表了当前屏幕上所需要渲染的每一个元素,包含了这些元素渲染所需要的内容。将Layer Tree抛给GPU线程,在GPU线程内调用Skia去完成整个UI的渲染过程。Layer Tree中有PictureLayer和TextureLayer两个比较重要的节点。PictureLayer主要负责屏幕图片的渲染,Flutter内部实现了一套图片解码逻辑,在IO线程将图片读取或者从网络上拉取之后,通过解码能够在IO线程上加载出纹理,交给GPU线程将图片渲染到屏幕上。但是由于音视频场景下系统API太过繁多,业务场景过于复杂。Flutter没有一套逻辑去实现跨平台的音视频组件,所以说Flutter提出了一种让第三方开发者来实现音视频组件的方式,而这些音视频组件的视频渲染出口,就是TextureLayer。
在整个Layer Tree渲染的过程中,TextureLayer的数据纹理需要由外部第三方开发者来指定,可以把视频数据和播放器数据送到TextureLayer里,由Flutter将这些数据渲染出来。
TextureLayer渲染过程:首先判断Layer是否已经初始化,如果没有就创建一个Texture,然后将Texture Attach到一个SufaceTexture上。
这个SufaceTexture是音视频的native代码可以获取到的对象,通过这个对象创建的Suface,我们可以将视频数据、摄像头数据解码放到Suface中,然后Flutter端通过监听SufaceTexture的数据更新就可以顺利把刚才创建的数据更新到它的纹理中,然后再将纹理交给SKIA渲染到屏幕上。
然而我们如果需要用Flutter实现美颜,滤镜,人脸贴图等等功能,就需要将视频数据读取出来,更新到纹理中,再将GPU纹理经过美颜滤镜处理后生成一个处理后的纹理。按Flutter提供的现有能力,必须先将纹理中的数据从GPU读出到CPU中,生成Bitmap后再写入Surface中,这样在Flutter中才能顺利的更新到视频数据,这样做对系统性能的消耗很大。
通过对Flutter渲染过程分析,我们知道Flutter底层需要渲染的数据就是GPU纹理,而我们经过美颜滤镜处理完成以后的结果也是GPU纹理,如果可以将它直接交给Flutter渲染,那就可以避免GPU-CPU-GPU这样的无用循环。这样的方法是可行的,但是需要一个条件,就是OpenGL上下文共享。
OpenGL
在说上下文之前,得提到一个和上线文息息相关的概念:线程。
Flutter引擎启动后会启动四个线程:
第一个线程是UI线程,这是Flutter自己定义的UI线程,主要负责GPU发出的VSync信号时候用当前Dart编译的机器码和当前运行环境创建出Layer Tree。
还有就是IO线程和GPU线程。和大部分OpenGL处理解决方案中一样,Flutter也采取一个线程责资源加载,一部分负责资源渲染这种思路。
两个线程之间纹理共享有两种方式。一种是EGLImage(IOS是 CVOpenGLESTextureCache)。一种是OpenGL Share Context。Flutter通过Share Context来实现纹理共享,将IO线程的Context和GPU线程的Context进行Share,放到同一个Share Group下面,这样两个线程下资源是互相可见可以共享的。
Platform线程是主线程,Flutter中有一个很奇怪的设定,GPU线程和主线程共用一个Context。并且在主线程也有很多OpenGL 操作。
这样的设计会给音视频开发带来很多问题,后面会详细说。
音视频端美颜处理完成的OpenGL纹理能够让Flutter直接使用的条件就是Flutter的上下文需要和平台音视频相关的OpenGL上下文处在一个Share Group下面。
由于Flutter主线程的Context就是GPU的Context,所以在音视频端主线程中有一些OpenGL操作的话,很有可能使Flutter整个OpenGL被破坏掉。所以需要将所有的OpenGL操作都限制在子线程中。
通过上述这两个条件的处理,我们就可以在没有增加GPU消耗的前提下实现美颜和滤镜等等功能。
TPM
在经过demo验证之后,我们将这个方案应用到闲鱼音视频组件中,但改造过程中发现了一些问题。
上图是摄像头采集数据转换为纹理的一段代码,其中有两个操作:首先是切进程,将后面的OpenGL操作都切到cameraQueue中。然后是设置一次上下文。然后这种限制条件或者说是潜规则往往在开发过程中容易被忽略的。而这个条件一旦忽略后果就是出现一些莫名其妙的诡异问题极难排查。因此我们就希望能抽象出一套框架,由框架本身实现线程的切换、上下文和模块生命周期等的管理,开发者接入框架以后只需要安心实现自己的算法,而不需要关心这些潜规则还有其他一些重复的逻辑操作。
在引入Flutter之前闲鱼的音视频架构与大部分音视频逻辑一样采用分层架构:
1:底层是一些独立模块
2:SDK层是对底层模块的封装
3:最上层是UI层。
引入Flutter之后,通过分析各个模块的使用场景,我们可以得出一个假设或者说是抽象:音视频应用在终端上可以归纳为视频帧解码之后视频数据帧在各个模块之间流动的过程,基于这种假设去做Flutter音视频框架的抽象。
咸鱼Flutter多媒体开源组件
整个Flutter音视频框架抽象分为管线和数据的抽象、模块的抽象、线程统一管理和上下文同一管理四部分。
管线,其实就是视频帧流动的管道。数据,音视频中涉及到的数据包括纹理、Bit Map以及时间戳等。结合现有的应用场景我们定义了管线流通数据以Texture为主数据,同时可以选择性的添加Bit Map等作为辅助数据。这样的数据定义方式,避免重复的创建和销毁纹理带来的性能开销以及多线程访问纹理带来的一些问题。也满足一些特殊模块对特殊数据的需求。同时也设计了纹理池来管理管线中的纹理数据。
模块:如果把管线和数据比喻成血管和血液,那框架音视频的场景就可以比喻成器官,我们根据模块所在管线的位置抽象出采集、处理和输出三个基类。这三个基类里实现了刚才说的线程切换,上下文切换,格式转换等等共同逻辑,各个功能模块通过集成自这些基类,可以避免很多重复劳动。
线程:每一个模块初始化的时候,初始化函数就会去线程管理的模块去获取自己的线程,线程管理模块可以决定给初始化函数分配新的线程或者已经分配过其他模块的线程。
这样有三个好处:
一是可以根据需要去决定一个线程可以挂载多少模块,做到线程间的负载均衡。第二,多线程并发式能够保证模块内的OpenGL操作是在当前线程内而不会跑到主线程去,彻底避免Flutter的OpenGL 环境被破坏。第三,多线程并行可以充分利用CPU多核架构,提升处理速度。
从Flutter端修改Flutter引擎将Context取出后,根据Context创建上下文的统一管理模块,每一个模块在初始化的时候会获取它的线程,获取之后会调用上下文管理模块获取自己的上下文。这样可以保证每一个模块的上下文都是与Flutter的上下文进行Share的,每个模块之间资源都是共享可见的,Flutter和音视频native之间也是互相共享可见的。
基于上述框架如果要实现一个简单的场景,比如画面实时预览和滤镜处理功能,
1:需要选择功能模块,功能模块包括摄像头模块、滤镜处理模块和Flutter画面渲染模块,
2:需要配置模块参数,比如采集分辨率、滤镜参数和前后摄像头设置等,
3:在创建视频管线后使用已配置的参数创建模块
4:最后管线搭载模块,开启管线就可以实现这样简单的功能。
上图为整个功能实现的代码和结构图。
结合上述音视频框架,闲鱼实现了Flutter多媒体开源组件。
组要包含四个基本组件分别是:
1:视频图像拍摄组件
2:播放器组件
3:视频图像编辑组件
4:相册选择组件
现在这些组件正在走内部开源流程。预计9月份,相册和播放器会实现开源。
后续展望和规划
1:实现开头所说的从底层SDK到UI的全链路的跨端开发。目前底层框架层和模块层都是各个平台各自实现,反而是Flutter的UI端进行了跨平台的统一,所以后续会将底层也按照音视频常用做法把逻辑下沉到C++层,尽可能的实现全链路跨平台。
2:第二部分内容为开源共建,闲鱼开源的内容不仅包括拍摄、编辑组件,还包括了很多底层模块,希望有开发者在基于Flutter开发音视频应用时可以充分利用闲鱼开源出的音视频模块能力,搭建APP框架,开发者只要去负责实现特殊需求模块就可以,尽可能的减少重复劳动。