You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AKS部署.NET版Teams录制机器人视频处理、ZIP存储及S3上传方案

Teams录制机器人视频流处理、本地打包及S3上传实现方案

一、补全视频流接收逻辑

你现有代码已经完成了视频套接字的事件订阅,只需要补全事件回调和数据结构即可,不要在回调线程里做重IO操作,避免阻塞媒体线程导致丢帧:

  1. 首先定义和音频缓冲区对齐的可序列化视频数据结构:
    public class SerializableVideoMediaBuffer
    {
        public string SocketId { get; set; }
        public long Timestamp { get; set; }
        public byte[] Buffer { get; set; }
        public string ParticipantId { get; set; }
        public bool IsVbss { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }
        public float Fps { get; set; }
    }
    
  2. 实现OnVideoMediaReceived和OnVbssMediaReceived回调,把收到的H264帧封装成上述结构,投递到VideoProcessor的队列中。注意Teams下发的H264是Annex-B格式的NALU,首帧会携带SPS/PPS参数集,不需要手动拼接,直接按接收顺序投递即可。
  3. 参会人视频套接字是动态绑定参会人流的,收到某Socket第一帧数据时,关联当前开摄像头的参会人ID即可,不需要提前初始化所有套接字的写入器。

二、实现VideoProcessor(对齐现有AudioProcessor架构)

完全复用你现有AudioProcessor的生产者-消费者模式,继承BufferBase<SerializableVideoMediaBuffer>,不需要调整现有媒体流框架逻辑:

  • 用FFmpeg.AutoGen做H264裸流到MP4容器的封装,不要做重编码,直接拷贝H264帧到MP4容器,CPU占用可以降到最低。部署时把对应平台的FFmpeg二进制打进AKS镜像即可,不需要额外服务。
  • 内部维护一个Dictionary<string, IntPtr>格式的写入器字典,key分别对应参会人ID、固定值vbss,收到首帧时初始化对应的MP4写入上下文,设置正确的时间基、分辨率、帧率参数。
  • Process方法里按时间戳顺序把H264帧写入对应上下文,不要跨帧打乱顺序,否则会出现花屏、音画不同步问题。
  • Finalise方法逻辑和音频完全对齐:先排空队列内剩余帧,然后写入MP4文件尾、释放所有FFmpeg上下文,输出所有生成的MP4文件路径。

三、统一ZIP打包逻辑

现有AudioProcessor的打包逻辑可以直接复用,不需要重写:

  1. 会议结束触发录制终止时,先等待AudioProcessor和VideoProcessor都执行完Finalise,拿到所有音频WAV、视频MP4的本地路径。
  2. 创建ZIP归档时按目录分类存放:
    • audio/目录存放所有参会人单独音频、混音音频文件
    • video/participants/目录存放每个参会人的摄像头视频文件
    • video/screen_share/目录存放VBSS屏幕共享录制文件
  3. 所有文件写入ZIP时用最优压缩级别,视频文件本身已经是压缩编码,压缩速度很快。写入完成后删除临时生成的原始WAV、MP4文件,只保留最终ZIP包。

四、S3存储上传实现

直接用官方AWSSDK.S3实现,兼容所有支持S3协议的对象存储服务:

  1. 扩展现有配置类,增加S3连接参数:访问密钥、私密密钥、服务地址、存储桶名称、是否启用路径样式访问。
  2. ZIP包生成完成后,用分块上传接口传文件,单块大小设为8MB,支持大文件断点续传,适配AKS网络波动场景。核心实现代码如下:
    public async Task UploadZipToS3(string localZipPath, string saveKey, IAzureSettings settings)
    {
        var s3Config = new AmazonS3Config
        {
            ServiceURL = settings.S3ServiceUrl,
            ForcePathStyle = settings.S3ForcePathStyle,
            Timeout = TimeSpan.FromMinutes(30)
        };
        using var client = new AmazonS3Client(settings.S3AccessKey, settings.S3SecretKey, s3Config);
        using var transferUtil = new TransferUtility(client);
        var request = new TransferUtilityUploadRequest
        {
            FilePath = localZipPath,
            BucketName = settings.S3BucketName,
            Key = saveKey,
            PartSize = 8 * 1024 * 1024,
            CannedACL = S3CannedACL.Private
        };
        await transferUtil.UploadAsync(request);
    }
    
  3. 上传成功后再删除本地ZIP临时文件,上传失败时保留本地文件做重试,避免录制文件丢失。

五、AKS部署注意事项

  • 镜像构建时把Linux版本的FFmpeg二进制拷入镜像,添加到PATH环境变量,确保FFmpeg.AutoGen可以正常加载。
  • 给Pod挂载emptyDir类型的临时存储卷,把录制临时目录指向该卷,避免容器根文件系统IO性能不足导致丢帧。
  • 资源配置按每路1080P视频流预留1核CPU、512M内存计算,避免封装过程中OOM导致录制文件损坏。
  • 离开会议时主动Dispose所有音频写入器、视频封装上下文,不要等GC回收,否则会出现MP4文件头未写入、文件无法播放的问题。

内容的提问来源于stack exchange,提问作者Aimeeting

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 12:15:34