惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
N
Netflix TechBlog - Medium
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Blog — PlanetScale
Blog — PlanetScale
Microsoft Security Blog
Microsoft Security Blog
D
Docker
WordPress大学
WordPress大学
罗磊的独立博客
J
Java Code Geeks
博客园 - 【当耐特】
博客园 - 司徒正美
雷峰网
雷峰网
H
Help Net Security
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
T
Tailwind CSS Blog
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
Recent Announcements
Recent Announcements
B
Blog

博客园 - zhuweisky

视频会议是如何实现AI会议纪要功能的? .NET 程序在装有企业防水墙的电脑上运行报错:内存不足 uni-app 实现视频聊天、屏幕分享,支持Android、HarmonyOS、iOS 去中心化的内网聊天软件Lachat是如何实现的? 实现鸿蒙(HarmonyOS)视频聊天、屏幕分享 实现一个纯血鸿蒙版(HarmonyOS)的聊天Demo,并可与其它PC、手机端互通! TCP反向代理:将局域网内部的TCP/HTTP服务暴露在公网上 C#实现屏幕墙:同时监控多个电脑桌面(支持Windows、信创Linux、银河麒麟、统信UOS) C#实现语音预处理:降噪、静音检测、自动增益(附Demo源码) 在IM即时通讯系统中接入DeepSeek等AI大模型 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS) 开发视频会议系统:使用GPU解码渲染视频 如何实现纯网页语音视频聊天和桌面分享?(附源码,PC版+手机版) Avalonia 实现聊天消息渲染、图文混排(支持Windows、Linux、信创国产OS) 如何实现安卓屏幕分享及视频聊天?(源码) C#实现聊天消息渲染、图文混排(支持Windows、Linux) C++调用C#的动态库dll 如何实现共享屏幕标注功能? C#推流RTMP,摄像头、麦克风、桌面、声卡(附源码) 如何让C/S应用支持多端(PC、Android、iOS)同时登录? 数据报表开发技巧:自动为数据报表添加【小计】、【总计】行 使用Xamarin开发手机聊天程序 -- 基础篇(大量图文讲解 step by step,附源码下载)
如何实现在服务端录制视频会议?
zhuweisky · 2024-10-28 · via 博客园 - zhuweisky

随着远程办公与异地协作越来越频繁,视频会议系统的使用也是越来越普遍。同时,用户对视频会议系统的功能也提出了更高的要求,比如,其中之一就是希望可以将整个视频会议的过程录制下来,以备之后可以查阅观看。

我们可以选择在视频会议系统的服务端或客户端来录制整个视频会议过程,在服务端录制与在客户端录制各有优劣。比如,在服务端录制对服务器配置要求更高,因为同时可能有很多个会议同时录制;而在客户端录制,录制的文件存放在客户端本地电脑上,只能在本地播放,如果其他人需要观看,则需要在录制完成后将该文件再上传到服务器。

无论是在服务端录制,还是在客户端录制,其技术原理是一样的。这里我就 傲瑞视频会议(OrayMeeting)在服务端(Windows、Linux、信创国产OS、银河麒麟、统信UOS)录制会议过程的技术原理和实现介绍给大家。

如下图就是某会议录制文件使用QQ影音播放的效果:

接下来,我们将具体介绍傲瑞视频会议是怎么实现会议录制的。

一. 录制流程说明

(1)会议信息中心包含了一个字段,用于指示该会议是否开启录制。

(2)当第一个人进入会议时,启动录制。

(3)当到会议结束时间:若会议室没有人,这立即结束录制;若会议室还有人,等最后一个人退出时,结束录制。

(3)任何时候,主持人结束会议,则将同时结束录制。

(4)中途若会议室没有人时,则暂停录制;当再有人进入会议时,则继续录制。

二. 傲瑞会议录制的画面布局

(1)录制画面最上面有一行高为30px标题栏,将实时显示如下信息:会议名称、系统时间、参会人数。

(2)标题栏下面的剩下区域为内容区,用来渲染用户视频/头像,或者是渲染用户分享屏幕的桌面图像。

(3)当参会人数不超过4个人时,采用2x2四宫格;当参会人数多于4个人时,采用3x3九宫格。

(4)录制时最多渲染9个人的视频或头像(3x3),开启了视频的用户排在最前面,其次是开启了麦克风的用户。

(5)如果用户开启了视频,录制时就渲染其视频图像,否则,就渲染该用户的默认头像。

(6)如果参会人员中有人开启了屏幕分享,这录制画面的内容区将不再渲染用户视频/头像,而是改为渲染被分享屏幕的桌面图像。

三. 程序实现技术要点

(1)获取参会人员的PCM声音数据和RGB图像数据。

使用 OMCS 提供的 MicrophoneConnector 和 DynamicCameraConnector 就可以获取每个参会人员的声音数据以及图像数据。

(2)拼接并渲染要录制的视频图像帧

在Windows可使用GDI+技术、在Linux上则可使用Skia技术来完成录制图像帧的拼接渲染。

if (desktopShare) //如果有人分享桌面,这主体内容区就是桌面图像
{
    //获取屏幕分享的最新桌面图像帧
    Image image = this.connectorManager.GetCurrentImage(null);
    canvas.SetDesktopImage(image);
}
else
{
    for (int i = 0; i < recordMembers.Count; i++)
    {
        string userID = recordMembers[i];
        Image image = null;
        if (!meeting.CamClosedMemberList.Contains(userID))
        {
            //获取参会成员的最新视频图像帧
            image = this.connectorManager.GetCurrentImage(userID);
        }
        
        DrawInfo renderModel = this.drawInfoManagers.Get(userID);
        renderModel.SetCameraImage(image);
        renderModel.SetMicState(!meeting.MuteMemberList.Contains(userID));
    }
    //绘制主体内容区
    canvas.SetCameraImage(this.drawInfoManagers.GetAll());
}
byte[] bytes = canvas.RenderImage(); //准备好要录制的图像
if (bytes != null)
{
    this.videoFileMaker?.AddVideoFrame(bytes); //提交给录制器    
}

(3)混音

使用 OMCS 提供的 MicrophoneConnectorMixer 可以将参会人员的声音混成一路。

IConnectorManager connectorManager = new OMCSConnectorManager(globalCache);
connectorManager.AudioMixed += ConnectorManager_AudioMixed;

private void ConnectorManager_AudioMixed(string userID, byte[] data)
{
    if (recording && data != null)
    {
        this.videoFileMaker?.AddAudioFrame(data);  //将混音数据提交给录制器        
    }
}

(4)定时器

使用定时器来调度声音数据和图像数据。比如:每隔10毫秒就从各个MicrophoneConnector获取一帧语音数据,并将它们混音。每隔40毫秒就从各个 DynamicCameraConnector 获取相应的图像数据,并将它们拼接,并按照前面描述的画面布局进行渲染。

//开启录制线程,定时调用
internal void StartRecord()
{
    recording = true;
    Task.Factory.StartNew(() =>
    {
        RecordThread();
    });
}

private void RecordThread()
{
    int sleepSeconds = 1000 / frameRate;
    while (true)
    {
        System.Threading.Thread.Sleep(sleepSeconds);
        //record ...
    }
}

(5)将图像帧和声音帧编码并生成MP4文件。

将混音好的声音数据、拼接好的渲染图像提交给 MFile,MFile会将它们编码并写入到MP4文件中。

会议结束时,将结束录制,并释放相关的资源。

internal void FinishRecord()
{
    recording = false;
    //释放麦克风、摄像头、桌面设备连接器
    connectorManager.DisconnectAllConnect();
    //释放录制器
    videoFileMaker?.Close(true);
}

四. 结语

在将录制会议的流程、画面布局、技术要点做了简单介绍后,相信大家对视频会议服务端在程序上是如何实现会议录制功能的,已经初步了解了。

本文只是粗略地介绍了视频会议录制的原理与技术实现,如果你有更具体的实现细节需要了解的,欢迎与我讨论。