Monibuca​monibuca.com

背景

市面上的流媒体服务器不可谓不多,从本人的第一份工作起,就一直接触和研究了形形色色的流媒体服务器,从最早的FCS(全称Flash Communication Server),后来改名为FMS(全称Flash Media Server),到Red5(java语言开发),到CrtmpServer(C++开发),让我对流媒体服务器的基本原理有了深刻的认识。当时本人痴迷C#,于是乎在业余时间对crtmpServer的代码进行移植,用C#仿照着写了一遍取名为csharprtmp,并且适当的增强了一些功能,于是对rtmp协议了如指掌。后来Adobe推出了RTMFP协议,是一种p2p协议,十分节省带宽。我就又开始研究一款名为OpenRTMFP的开源项目,后来该项目改名为MonaServer。我在起基础上进行了扩展,实现了一些例如录制flv,shareObject等原本FMS有的功能。后开发出了HTML5直播技术(现在命名为Jessibuca,尚未开源),采用的传输协议就是WebSocket传输裸的视频流的方式,属于私有协议。而Server当时就使用的MonaServer。但当时遇到一个问题,C++的内存泄漏问题,这个一直没有很好的解决。遂决定放弃使用MonaServer转而使用srs,而srs要用一个很简单的go写的小程序将http-flv转换成WebSocket的Flv来适配我的Jessibuca,感觉最好能直接修改srs来实现这个功能。对srs的源码研究了一小段时间后放弃了,因为C++代码过于难写,容易出现bug。后来转而使用golang写的gortmp作为server,同样对其进行了扩展,而且进展十分顺利,golang的开发效率令人惊叹,而且其协程的特性很完美的处理了流媒体服务器的并发的场景。所以使用golang写的流媒体服务器项目很多,github上随便一搜就有很多,比如livego、joy4等。期间还接触到一位使用Node.js实现的流媒体服务器Node Media Server,我也和作者交流了许多,收益良多。

现有项目的不足

虽然流媒体服务器项目很多,但在我使用过程中遇到了几个痛点功能太多太重,往往大而全,不够轻量 很多号称轻量的项目最后都会越来越重

扩展性弱,由于功能复杂,设计之初没有提供良好的扩展性,有些项目带有脚本支持,如FMS和MonaServer,但执行脚本会牺牲性能,而且脚本和原生代码相比,功能限制很大,只能实现业务逻辑而不是流媒体服务器本身的功能扩展。

缺少图形管理界面,FMS是配套有图形管理界面的,当然FMS的问题是商业软件需要付费,源码也是不可见的。

综上所述,本人在吸收了以上诸多流媒体服务器的设计后,完成了Monibuca这款golang编写的流媒体开发框架的编写

受到vue渐进式思想的影响

vue渐进式框架的设计思想非常棒,那么是否可以用来设计流媒体服务器,使得流媒体服务器不只是一个服务器,而是一个开发框架,让开发者可以定制化自己的流媒体服务器呢?答案是肯定的。当然我们需要更多的抽象。

如何实现可扩展——插件化

许多IDE和编辑器都依靠插件化技术得以拓展其功能,并形成其生态,例如vs、vs code、eclipse、jetbrains系列,当然vue作为一个前端框架也是设计了很不错的插件机制。这些都可以作为借鉴。

要实现流媒体服务器的插件化,就需要把核心功能和拓展功能分离,进行足够的抽象。

三大抽象概念发布者(Publisher)

订阅者(Subscriber)

房间(Room)

发布者(Publisher)

发布者本质上就是输入流,其抽象行为就是将音频和视频数据压入房间中,换句话说,就是在恰当的时候调用房间的PushVideo和PushAudio函数 ::: tip 源码位置 发布者定义位于monica/publisher.go中 ::: 在发布者的定义中有一个InputStream的结构体,用来和房间进行互操作。 所有具体的发布者都应该包含这个InputStream,以组合继承的方式成为发布者。 该InputStream包含最核心功能就是Publish函数,这个函数的功能就是在房间里面设置发布者是自己,这个行为就是发布。形象的理解就是主播走进了房间。 引擎不关心是谁走进了房间,也不关心进来的人会发布什么内容。 ::: tip 发布者插件 所有实现了发布者具体功能的插件,就是发布者插件,这样一来,流媒体的媒体源可以是任意的形式,比如RTMP协议提供的推流,可以由FFMPEG、OBS发布。也可以是读取本地磁盘上的媒体文件,也可以来自源服务器的私有协议传输的内容。 :::

订阅者(Subscriber)

订阅者就是输出流,其抽象行为就是被动接收来自房间的音频和视频数据。 ::: tip 源码位置 订阅者定义位于monica/subscriber.go中 ::: 订阅者有两个函数sendVideo和sendAudio用于接收音频和视频数据。这个两个函数会对音视频做一些预处理,主要是实现丢包机制、时间戳和首屏渲染。具体的视频数据会共享读取。 然后调用SendHandler将打包好的音视频数据发送到具体的订阅者那里。 ::: tip 订阅者插件 订阅者插件,本质上就是SendHandler函数。具体可以将打包的数据以何种协议输出,还是写入文件,由插件实现。 :::

房间(Room)

房间就是一个连接发布者和订阅者的地方。可以形象的理解为主播的房间,发布者是主播,订阅者就是粉丝观众。房间是引擎的核心,其重要逻辑包括: 1. 房间的创建、查询、关闭 2. 订阅者的加入和移除 3. 发布者的进入和离开。 ::: tip 源码位置 订阅者定义位于monica/room.go中 :::

流媒体服务器的核心是转发二字。当你去研究一款流媒体服务器的时候,会有海量的代码阻碍你看清其核心逻辑。包括:多媒体格式定义、解析,如Flv、MP4、MP3、H264、AAC等等

传输协议的解析,如RTMP家族、AMF、HTTP、RTSP、HLS、WebSocket等等

各种工具类,用来读取字节的缓冲、大小端转换、加解密算法、等等

大部分流媒体服务器都是基于rtmp协议之上扩展而来,这是历史原因造成的,所以功能不能很好的分离,耦合度很高。往往牵一发而动全身。其实所谓的流媒体服务器本质上就是把发布者的数据经过服务器转发到订阅者手里播放,起一个中转作用。至于什么协议格式,什么媒体格式都是属于扩展功能。所以最轻量的服务器应该不包含任何协议格式,任何媒体格式,仅仅只是完成中转。再说的直白一点核心代码就是一个for循环。

for _, v := range r.Subscribers {

v.sendVideo(video)

}

其他都是围绕这个for循环展开。所有的流媒体服务器代码里面都有这个for循环,写法稍有不同,但本质相同。 ::: tip 源码位置 该核心逻辑位于monica/room.go中的Run函数内 :::

如何实现高性能

流媒体服务器对性能要求极为苛刻。因为流媒体服务器属于高速系统,会有并发的长连接请求,协议封包解包和音视频格式的编解码都消耗着CPU以及内存,如何尽可能的减少消耗是必须考虑的问题。

内存使用

池化是一个不错的选择,所以尽量池化,在Monibuca中对[]byte类型,采用了github.com/funny/slab包来管理。其他结构体就用系统自带的pool包来池化对象。

协程的使用

golang自带的goroutine可以有效的减少线程的使用,并可以支持各种异步并发的情况。合理的创建goroutine很重要,这样才能尽可能高效利用CPU时间。 在monibuca中,创建goroutine在如下场景中: 1. 通讯协议建立的长连接对于一个goroutine 2. 每个房间拥有一个goroutine用于接收指令和转发音视频数据 3. 每一个插件会使用一个goroutine来执行插件的Run函数

由于引擎本身比较轻量化,更多的性能的优化需要插件提供者自由发挥了。

更新:上面内容已经过时,monibuca已经进入2.0时代,参考这篇文章:李宇翔:重新定义流媒体服务器​zhuanlan.zhihu.com

go srs 流媒体服务器_Go语言实现的流媒体服务器开发框架相关推荐

  1. 易语言 上传文件到远程服务器,易语言与向远程服务器发送文件夹

    易语言与向远程服务器发送文件夹 内容精选 换一换 一.IDEA连接SSH 确认你的密码输对了,还好我保存了我的远程服务器的密码,原先我一直以为我输对了,导致一直报错Auth fail 点击ok,连接上 ...

  2. 易语言 html 服务器,易语言模拟网页Web服务器源代码

    .版本 2 .支持库 internet .子程序 __启动窗口_创建完毕 ' 实在是无聊,做了一个WEB服务器,可以把对方的网站拿回来模拟 ' 程序运行后在IE地址栏里面打 可以发现网站 ' 如果你简 ...

  3. 2022-07-25:xiu是用rust语言编写的流媒体服务器软件项目。k8s安装xiu,drone文件如何写?

    2022-07-25:xiu是用rust语言编写的流媒体服务器软件项目.k8s安装xiu,drone文件如何写? 答案2022-07-25: 云原生环境不可能完全一样,只能做参考. 我采用的是dron ...

  4. 默默前行的livego--基于go语言的rtmp直播服务器

    转载地址:http://blog.csdn.net/sweibd/article/details/76229296 为什么go语言,原因太多了! 轻量级协程,随时goroutine 方便的channe ...

  5. linux下用C语言实现TCP/IP服务器与客户端互相发送数据的socket编程

    linux下用C语言实现TCP/IP服务器与客户端互相发送数据的socket编程 server.c #include <sys/stat.h>#include <fcntl.h> ...

  6. go语言入门经典_Go 语言中的 gRPC 基础入门

    01 为什么使用 gRPC? 借助 gRPC,我们可以在 .proto 文件中一次定义我们的服务,并以 gRPC 支持的任何语言生成客户端和服务器代码,无论是在大型数据中心内的服务器,还是在个人的电脑 ...

  7. 服务器系统怎么写,服务器操作系统语言写的

    服务器操作系统语言写的 内容精选 换一换 简要介绍PHP-FPM(PHP FastCGI Process Manager),PHP FastCGI进程管理器,用于管理PHP进程池的软件,用于接受web ...

  8. 易语言远程查询oracle数据库连接,易语言如何连接远程服务器上的数据库,并读取数据...

    标签: 用易语言来连接远程服务器上的数据库,可以使用支持库中的方法. 连接数据库方法名: 连接mysql(服务器地址,用户名,密码,数据库名,端口号) 注意:连接mysql()这个方法名,如果没有,单 ...

  9. go语言视频教程_ go语言入门视频教程_go语言实战视频教程

    许多人可能知道go语言的优点在哪里,但他们不知道go语言适合在哪里使用.通过学习go语言视频教程,可以清楚的知道go语言主要用于服务器端开发,其定位是用来开发"大型软件".学习go ...

  10. 服务器常用语言,计算机常用词汇--语言及服务器篇

    计算机语言指用于人与计算机之间通讯的语言,是人与计算机之间传递信息的媒介.接下来小编为大家整理了计算机常用词汇--语言及服务器篇,希望对你有帮助哦! 一.计算机语言 CSS: Cascading St ...

最新文章

  1. Laravel5 打印SQL
  2. 每日两SQL(9),欢迎交流~
  3. Spring AOP 应用篇
  4. JDK 9 @不建议使用的注释增强功能
  5. opencv:灰色和彩色图像的像素直方图及直方图均值化的实现与展示
  6. 《Python Cookbook 3rd》笔记(5.14):忽略文件名编码
  7. java线程如何避免死锁_Java面试问题,如何避免Java线程中的死锁?
  8. 小兔的棋盘(HDU-2067)
  9. 2017.9.27 可持久化并查集 失败总结
  10. php如何递归算法,详细的介绍一下PHP递归算法_PHP教程
  11. 数据结构排序系列详解之四 快速排序
  12. Myeclipse破解后报错解决
  13. java 网易邮箱_Java mail 163邮箱配置
  14. Nexus 6p 刷入TWRP和OPENGAPPS
  15. 蓝桥杯:调和级数————Python
  16. python可以实现的功能_Python功能点实现:数据热更新
  17. Ubuntu分区扩容
  18. XMind中的鱼骨图
  19. web2.0图形设计风格指南
  20. idea配置开启Run DashBoard

热门文章

  1. 使用 customize-cra 修改 webpack 配置
  2. H5页面自定义标题、链接、描述、图片分享到微信朋友、朋友圈、QQ和QQ空间
  3. 计算机学报编辑待遇,《计算机学报》编辑委员会
  4. java 安全策略_java.security.Security 支持的安全策略和算法
  5. 【机器学习面经】AI算法岗位简历必备
  6. 计算机应用中格式刷怎么用,如何连续使用格式刷【搞定手段】
  7. Annotation-specified bean name conflicts with existing
  8. 2015 年电赛测评试题——多种波形发生器
  9. linux snoop抓包命令,snoop抓包简介
  10. PHP方法,传入的参数前带三个点是什么意思?