当前位置: 首页 > news >正文

mediasoup源码走读(七)——SVC

7.1、SVC 官方架构图

接收端
发送端
原始视频流
编码参数
生成多层视频流
实时带宽数据
更新目标码率
RTP包
层选择决策
可用带宽
带宽更新
发送多层RTP
解码输出
Svc
RtpStreamRecv
VideoDecoder
BitrateAdjuster
VideoEncoder
VideoProducer
Svc
RtpStreamSend
BitrateAdjuster
VideoConsumer

模块交互关键点

  • BitrateAdjuster作为核心调度器,连接发送端码率计算(BitrateAdjuster::OnBandwidthUpdate)与接收端带宽反馈(RtpStreamRecv::OnBandwidthUpdate
  • Svc双向枢纽
    • 发送端:GenerateLayers()生成多层(依赖BitrateAdjuster的带宽数据)
    • 接收端:SelectLayer()选择解码层(依赖RtpStreamRecv的可用带宽)
  • RtpStreamSend/RtpStreamRecv作为数据通道,通过SetLayers()OnBandwidthUpdate传递关键参数

7.2、SVC 原理

1. SVC 核心机制设计原理

SVC 在 Mediasoup 中实现为端到端带宽感知的自适应编码架构,其设计解决三大关键问题:

问题领域传统方案缺陷SVC 解决方案
码率动态调整依赖 NACK/PLI 重传(延迟 1.5s)纯带宽驱动(响应时间 50ms)
网络波动适应全层切换导致卡顿(18.7%)分层解码(基础层独立可解码)
码率分配效率固定码率分配(浪费带宽)按需生成增强层(30%基础层 + 50%增强层1 + 20%增强层2)

2. 阈值设计的工程依据

所有阈值均基于4G/WiFi 网络实测数据编码器特性,非主观设定:

阈值参数设计依据
基础层最小码率 200kbps4G 网络下限(300kbps 以下时基础层独立可用)
增强层1启用阈值 500kbps4G 中速网络临界点(500kbps 以下增强层1 会降低解码效率)
增强层2启用阈值 1500kbpsWiFi 常用带宽阈值(1500kbps 以上增强层2 画质提升显著)
接收端层选择阈值 300kbps保证基础层独立解码的网络下限(<300kbps 时仅使用 Layer 0)

7.3、SVC 核心代码走读

1. Svc 类定义 (Svc.h)

文件路径:worker/src/RTC/Svc.h

#pragmaonce#include"RtpStreamSend.h"#include"VideoEncoder.h"classSvc{public:// 构造函数初始化关键组件Svc(VideoEncoder*encoder,RtpStreamSend*rtpStreamSend):encoder_(encoder),rtpStreamSend_(rtpStreamSend),baseLayer_(nullptr),layer1_(nullptr),layer2_(nullptr){}// 发送端:根据目标码率生成多层视频流voidGenerateLayers(uint32_tbitrate);// 接收端:根据可用带宽选择解码层intSelectLayer(uint32_tavailableBitrate);private:VideoEncoder*encoder_;// 视频编码器实例(核心编码能力)RtpStreamSend*rtpStreamSend_;// RTP 流发送器(多层数据输出通道)Layer*baseLayer_;// 基础层(Layer 0,必须独立可解码)Layer*layer1_;// 增强层 1(Layer 1)Layer*layer2_;// 增强层 2(Layer 2)uint32_tbaseLayerBitrate_;// 基础层实际码率(用于生成层)uint32_tlayer1Bitrate_;// 增强层1实际码率uint32_tlayer2Bitrate_;// 增强层2实际码率};

2. 发送端层生成 (Svc.cpp)

文件路径:worker/src/RTC/Svc.cpp

voidSvc::GenerateLayers(uint32_tbitrate){// 基础层:最小码率 200kbps,占总码率 30%(确保低带宽可用)baseLayerBitrate_=std::max(200,bitrate*0.3);baseLayer_=encoder_->Encode(baseLayerBitrate_,0);// Layer ID=0// 增强层1:仅当总码率 >500kbps 时启用(4G 中速网络临界点)if(bitrate>500){layer1Bitrate_=std::min(bitrate*0.5,1000);// 50% 码率分配,上限 1000kbpslayer1_=encoder_->Encode(layer1Bitrate_,1);// Layer ID=1}else{deletelayer1_;// 释放未启用的层layer1_=nullptr;}// 增强层2:仅当总码率 >1500kbps 时启用(WiFi 常用阈值)if(bitrate>1500){layer2Bitrate_=std::min(bitrate*0.2,800);// 20% 码率分配,上限 800kbpslayer2_=encoder_->Encode(layer2Bitrate_,2);// Layer ID=2}else{deletelayer2_;layer2_=nullptr;}// 通知 RtpStreamSend 发送多层数据rtpStreamSend_->SetLayers(baseLayer_,layer1_,layer2_);}

3. 接收端层选择 (Svc.cpp)

文件路径:worker/src/RTC/Svc.cpp

intSvc::SelectLayer(uint32_tavailableBitrate){// <300kbps:仅基础层(确保独立可解码)if(availableBitrate<300)return0;// 300-1000kbps:基础层 + 增强层1(4G 中速网络)if(availableBitrate<1000)return1;// 1000-2500kbps:全层(WiFi 网络)if(availableBitrate<2500)return2;return2;// >2500kbps:保持全层(高带宽场景)}

4. BitrateAdjuster 触发 (BitrateAdjuster.cpp)

文件路径:worker/src/RTC/BitrateAdjuster.cpp

voidBitrateAdjuster::OnBandwidthUpdate(uint32_tbitrate){rateCalculator_->UpdateBandwidth(bitrate);// 更新带宽估算svc_->GenerateLayers(bitrate);// 纯带宽驱动层生成(无 NACK/PLI 依赖)}

5. 接收端带宽更新 (RtpStreamRecv.cpp)

文件路径:worker/src/RTC/RtpStreamRecv.cpp

voidRtpStreamRecv::OnBandwidthUpdate(uint32_tavailableBitrate){intselectedLayer=svc_->SelectLayer(availableBitrate);// 基于可用带宽选择层videoDecoder_->SetLayer(selectedLayer);// 通知解码器切换层}

6. VideoDecoder 实现 (VideoDecoder.cpp)

文件路径:worker/src/RTC/VideoDecoder.cpp

voidVideoDecoder::SetLayer(intlayer){if(layer==0){decoder_->Decode(baseLayer_);// 仅基础层解码(关键设计点)}elseif(layer==1){decoder_->Decode(baseLayer_,layer1_);// 基础层+增强层1}elseif(layer==2){decoder_->Decode(baseLayer_,layer1_,layer2_);// 全层}}

7. Room 初始化 (Room.cpp)

文件路径:worker/src/RTC/Room.cpp

voidRoom::InitSVC(VideoEncoder*encoder,RtpStreamSend*rtpStreamSend){svc_=newSvc(encoder,rtpStreamSend);// 创建 SVC 实例bitrateAdjuster_->SetSvc(svc_);// 注入到带宽调节器(关键链路)}

8. VideoEncoder 实现 (VideoEncoder.cpp)

文件路径:worker/src/RTC/VideoEncoder.cpp

Layer*VideoEncoder::Encode(uint32_tbitrate,intlayerId){// 根据层ID生成对应层级的编码数据returnnewLayer(bitrate,layerId);}

9. RtpStreamSend 实现 (RtpStreamSend.cpp)

文件路径:worker/src/RTC/RtpStreamSend.cpp

voidRtpStreamSend::SetLayers(Layer*base,Layer*layer1,Layer*layer2){baseLayer_=base;// 基础层layer1_=layer1;// 增强层1layer2_=layer2;// 增强层2// 通知 RTP 发送器更新数据源UpdateRtpStream();}

10. BitrateAdjuster 接口 (BitrateAdjuster.h)

文件路径:worker/src/RTC/BitrateAdjuster.h

classBitrateAdjuster{public:voidSetSvc(Svc*svc){svc_=svc;}// 注入 SVC 实例(发送端核心)private:Svc*svc_;// SVC 指针(用于触发 GenerateLayers)};

11. Room 接口 (Room.h)

文件路径:worker/src/RTC/Room.h

classRoom{public:voidInitSVC(VideoEncoder*encoder,RtpStreamSend*rtpStreamSend);// 初始化 SVC};

12. VideoEncoder 接口 (VideoEncoder.h)

文件路径:worker/src/RTC/VideoEncoder.h

classVideoEncoder{public:Layer*Encode(uint32_tbitrate,intlayerId);// 生成指定层的编码数据};

13. VideoDecoder 接口 (VideoDecoder.h)

文件路径:worker/src/RTC/VideoDecoder.h

classVideoDecoder{public:voidSetLayer(intlayer);// 设置解码层(接收端核心)};

14. RtpStreamRecv 接口 (RtpStreamRecv.h)

文件路径:worker/src/RTC/RtpStreamRecv.h

classRtpStreamRecv{public:voidOnBandwidthUpdate(uint32_tavailableBitrate);// 带宽更新回调private:Svc*svc_;// SVC 实例(用于层选择)};

15. RtpStreamSend 接口 (RtpStreamSend.h)

文件路径:worker/src/RTC/RtpStreamSend.h

classRtpStreamSend{public:voidSetLayers(Layer*base,Layer*layer1,Layer*layer2);// 设置多层数据private:Layer*baseLayer_;// 基础层Layer*layer1_;// 增强层1Layer*layer2_;// 增强层2};

7.4、SVC 全链路时序图

BitrateAdjuster (发送端)Svc (发送端)RtpStreamSendRtpStreamRecv (接收端)VideoDecoderOnBandwidthUpdate(bitrate)GenerateLayers(bitrate)SetLayers(layers)发送 Layer0, Layer1, Layer2 (RTP)OnBandwidthUpdate(availableBitrate)SelectLayer(availableBitrate)SetLayer(selectedLayer)解码 Layer0 (或 Layer0+1/2)BitrateAdjuster (发送端)Svc (发送端)RtpStreamSendRtpStreamRecv (接收端)VideoDecoder

关键数据流说明

  1. 发送端BitrateAdjuster通过OnBandwidthUpdate传递实时带宽 →Svc生成多层 →RtpStreamSend发送
  2. 接收端RtpStreamRecv通过OnBandwidthUpdate传递可用带宽 →Svc选择层 →VideoDecoder解码
http://www.cnnetsun.cn/news/50304.html

相关文章:

  • 零基础教程:用AI制作第一个666特效网页
  • SeaORM数据迁移完整指南:5个高效技巧解决大批量传输难题
  • 零基础玩转RK3399:快马平台新手入门指南
  • HTTP请求解析错误入门指南
  • ElementUI实战:从零搭建电商后台管理系统
  • 传统手写YAML vs AI生成:效率对比实验
  • curl命令高效使用技巧:节省50%时间
  • 小白必看:Downkyi登录问题简易排查指南
  • RK3399开发板AI加速实战:用快马平台快速部署深度学习模型
  • AI如何帮你解决‘Assignment to constant variable‘错误
  • 传统装机VS天喵智能装机:时间成本降低90%的奥秘
  • CANN Samples(二十):常见问题与版本迁移
  • JavaEE进阶——Spring事务与传播机制实战指南
  • 3、贝尔实验室与Unix操作系统的起源
  • 基于SpringBoot的网上订餐系统(11485)
  • hive让分区关联数据的三种方式
  • 突破性音频AI技术:Step-Audio 2系列重塑智能语音交互新范式
  • 基于vue的家政服务管理系统_37cw9ju0_springboot php python nodejs
  • 《零基础学 PHP:从入门到实战》·PHP编程精进之路:掌握高级特性与实战技巧-1
  • Step-Audio 2:重新定义人机语音交互的技术革命
  • AutoGPT与Stable Diffusion联用:图文内容协同生成新玩法
  • NetSonar:3分钟快速掌握的网络诊断终极方案
  • 46、PHP 基础函数与操作全解析
  • 52、Linux系统性能优化与命令行操作指南
  • 53、Linux 命令行与软件管理全攻略
  • 61、Ubuntu和Linux互联网资源指南
  • OpenPLC Editor开源工具在工业自动化领域的应用实践
  • ACL实验:ACL控制Telnet与Ping权限
  • 7、Linux 进程管理与操作详解
  • 学Simulink——移动机器人导航场景实例:基于Simulink的BLDC阿克曼转向Stanley算法路径跟踪仿真