WebRTC 视频编码丢帧与降低分辨率机制深度剖析

关键词:WebRTC、视频编码、帧丢弃、分辨率降级、自适应码率、视频质量控制


一、为什么需要丢帧和降分辨率?

在实时音视频通信中,网络带宽和终端 CPU 是两个最常见的瓶颈。当网络带宽不足时,如果继续以高分辨率、高帧率发送视频,就会造成:

  • 网络拥塞:数据包在路由器队列中积压,延迟急剧上升;
  • 丢包率升高:数据包被网络中间节点丢弃,画面出现马赛克;
  • 编码质量下降:编码器被迫用更高 QP(量化参数)压缩图像,花屏严重。

当终端 CPU 过载时,编码时延超过帧间隔,就会造成帧率下降、卡顿,甚至整个系统响应缓慢。

WebRTC 的解决方案是构建一套多层次、自适应的视频质量控制体系,在保证通话流畅的前提下,动态地调整帧率、分辨率和码率。


二、整体架构一览

WebRTC 视频发送链路的质量控制涉及以下几个核心模块:

复制代码
摄像头/采集源
      │
      ▼
[VideoAdapter]         ← 源端帧率控制 & 分辨率缩放(裁剪 + 缩放)
      │
      ▼
[VideoStreamEncoder]   ← 核心编码器管理,多重丢帧决策点
      │
      ├── [FrameDropper]           ← 漏桶算法丢帧(码率过载保护)
      ├── [CongestionWindow Drop]  ← 拥塞窗口回退丢帧
      ├── [EncoderQueue Drop]      ← 编码队列积压丢帧
      └── [DropDueToSize]          ← 分辨率-码率不匹配丢帧
      │
      ▼
[实际编码器 H264/VP8/VP9/AV1]
      │
      ▼
[ResourceAdaptationProcessor]  ← 自适应降级决策中枢
      ├── [OveruseFrameDetector]   ← CPU 过载检测
      ├── [QualityScaler]          ← QP 质量监控
      └── [VideoStreamAdapter]     ← 降分辨率 / 降帧率执行

下面我们逐层深入每一个模块的实现细节。


三、第一层:VideoAdapter------源端帧率与分辨率控制

VideoAdapter(路径:media/base/video_adapter.cc)是视频流在进入编码器之前的第一道"关卡",承担两项核心职责:

  1. 帧率控制:根据目标帧率决定是否丢弃当前帧;
  2. 分辨率适配:将输入帧裁剪(Crop)并缩放(Scale)到目标分辨率。

3.1 核心入口函数 AdaptFrameResolution()

cpp 复制代码
bool VideoAdapter::AdaptFrameResolution(
    int in_width, int in_height, int64_t in_timestamp_ns,
    int* cropped_width, int* cropped_height,
    int* out_width, int* out_height)

返回值说明

  • true:帧应该被保留并编码(同时输出裁剪/缩放后的尺寸);
  • false:帧应该被丢弃。

完整决策流程图如下:

复制代码
AdaptFrameResolution() 入口
         │
         ▼
  计算 max_pixel_count   ← 取 resolution_request 和 output_format_request 中更严格的限制
         │
         ▼
  max_pixel_count <= 0 ?  ──是──▶  丢帧(return false)
         │否
         ▼
  DropFrame(timestamp) ?  ──是──▶  丢帧(return false)
         │否
         ▼
  计算目标宽高比(横/竖屏分别处理)
         │
         ▼
  FindScale() 计算最佳缩放比例
         │
         ▼
  roundUp() 对齐 resolution_alignment_
         │
         ▼
  计算 out_width / out_height
         │
         ▼
  scale_resolution_down_to 是否有值?
         │是                     │否
         ▼                       ▼
  进一步限制输出尺寸         直接输出结果
         │
         ▼
  输出裁剪 & 缩放后的尺寸(return true)

3.2 帧率控制:DropFrame()

cpp 复制代码
bool VideoAdapter::DropFrame(int64_t in_timestamp_ns) {
    int max_fps = max_framerate_request_;
    if (output_format_request_.max_fps)
        max_fps = std::min(max_fps, *output_format_request_.max_fps);
    framerate_controller_.SetMaxFramerate(max_fps);
    return framerate_controller_.ShouldDropFrame(in_timestamp_ns);
}

FramerateController 是一个简单的令牌桶(Token Bucket),根据时间戳判断当前帧是否需要被丢弃。比如目标 15fps,当前输入 30fps,就会丢弃一半的帧。

max_fps 来自两个来源,取最小值:

  • max_framerate_request_:来自 OnSinkWants(),由下游(编码器)设置;
  • output_format_request_.max_fps:来自 OnOutputFormatRequest(),由应用层或采集源设置。

3.3 分辨率缩放:FindScale() 算法

FindScale() 函数是分辨率降级的核心算法,它使用交替缩放策略寻找最接近目标像素数的缩放比:

复制代码
初始状态: scale = 1/1
    │
    ▼  交替缩放步骤:× 3/4 和 × 2/3
1280×720 → (×3/4) → 960×540
         → (×2/3) → 640×360
         → (×3/4) → 480×270
         → (×2/3) → 320×180
         → (×3/4) → 240×135
         → (×2/3) → 160×90

算法规则:

  • 如果输入宽高均为 3 的倍数,首先以 2/3 缩放;
  • 之后交替乘以 3/4 和 2/3;
  • 在所有满足 output_pixels <= max_pixels 的候选中,选择与 target_pixels 差值最小的那个。

为何选择 3/4 和 2/3 交替而非简单的 1/2?

因为 1/2 的步长过大,会从 1080p 直接跳到 540p,中间缺少过渡档位。3/4 × 2/3 ≈ 0.5,两步合计效果相当于缩减一半,但中间增加了一个过渡点(如 960×540),使画质变化更平滑。

缩放比例参数含义:

参数 含义
target_pixel_count 目标像素数,尽量接近该值
max_pixel_count 像素数上限,不能超过
scale.numerator / scale.denominator 分数形式的缩放比(先约分)

分辨率对齐: 输出尺寸必须是 resolution_alignment_ 的整数倍(由编码器要求决定,常见值为 2、4、16),通过 roundUp() 向上取整但不超过原始尺寸。

3.4 外部控制接口

接口 调用方 作用
OnOutputFormatRequest() 采集源/应用层 设置最大分辨率、帧率、目标宽高比
OnSinkWants() 编码器/下游 Sink 设置 max_pixel_count、max_fps、resolution_alignment
AdaptFrameResolution() 视频处理管线 每帧调用,获取帧是否丢弃及输出尺寸

四、第二层:VideoStreamEncoder------多重丢帧决策

VideoStreamEncoder(路径:video/video_stream_encoder.cc)是 WebRTC 视频发送链路的核心枢纽,在帧进入实际硬件/软件编码器之前,设置了四道丢帧防线

4.1 第一道防线:编码队列积压 & 拥塞窗口丢帧

复制代码
OnIncomingFrame()
      │
      ├── queue_overload(编码队列积压)?  ──是──▶ 丢帧(kEncoderQueue)
      │
      └── cwnd_frame_drop(拥塞窗口回退)? ──是──▶ 丢帧(kCongestionWindow)
      │
      └── 进入 MaybeEncodeVideoFrame()

拥塞窗口丢帧(cwnd_frame_drop) 是网络拥塞控制的一部分:

cpp 复制代码
// 当 cwnd 压缩比 > 1% 且目标码率高于编码器最低码率时
if (cwnd_reduce_ratio > 0.01 && target_bitrate.bps() > 0 &&
    target_bitrate.bps() > send_codec_.minBitrate * 1000) {
    // 计算每隔多少帧丢一帧(最多丢一半:间隔最小为 2)
    cwnd_frame_drop_interval_ = std::max(
        2, static_cast<int>(target_bitrate.bps() / reduce_bitrate_bps));
}

cwnd_frame_counter_++ % cwnd_frame_drop_interval_.value() == 0 即每隔 N 帧丢一帧(N ≥ 2,即最多丢 50% 帧)。

为何不直接降低编码分辨率? 因为拥塞窗口反馈是瞬时的,丢帧响应更快(毫秒级),而调整编码器配置需要重新初始化,响应慢(百毫秒级)。

4.2 第二道防线:时间戳异常丢帧

cpp 复制代码
if (incoming_frame.ntp_time_ms() <= last_captured_timestamp_) {
    // 时间戳相同或倒退,丢弃此帧
    ProcessDroppedFrame(incoming_frame, kBadTimestamp);
    return;
}

此处保证视频帧的 NTP 时间戳严格单调递增,避免 RTP 时间线混乱。

4.3 第三道防线:分辨率-码率不匹配丢帧(DropDueToSize)

cpp 复制代码
bool VideoStreamEncoder::DropDueToSize(uint32_t source_pixel_count) const {
    // ...
    if (bitrate_bps < 300000 /* qvga */) {
        return pixel_count > 320 * 240;   // 码率<300kbps但分辨率>QVGA,丢帧
    } else if (bitrate_bps < 500000 /* vga */) {
        return pixel_count > 640 * 480;   // 码率<500kbps但分辨率>VGA,丢帧
    }
    return false;
}

对应的码率-分辨率阈值表:

当前可用码率 允许的最大分辨率 说明
< 300 kbps 320×240(QVGA) 低码率强制限制分辨率
300~500 kbps 640×480(VGA) 中低码率允许 VGA
≥ 500 kbps 无限制(由编码器配置决定) 正常码率范围
编码器有码率限制 ResolutionBitrateLimits 决定 优先使用编码器提供的限制

DropDueToSize() 返回 true 时,帧会被存入 pending_frame_,同时通知 stream_resource_manager_.OnFrameDroppedDueToSize(),触发分辨率降级流程(详见第五章)。

4.4 第四道防线:编码器暂停(EncoderPaused)

cpp 复制代码
bool VideoStreamEncoder::EncoderPaused() const {
    // 当目标码率为 0(网络断了)时,编码器进入暂停状态
    return encoder_target_bitrate_bps_.value_or(0) == 0;
}

暂停时帧同样存入 pending_frame_,恢复后发送最新的一帧(避免发送已经过时的帧)。


五、第三层:FrameDropper------漏桶算法精细丢帧

FrameDropper(路径:modules/video_coding/utility/frame_dropper.cc)是基于漏桶(Leaky Bucket)算法 实现的码率过载保护器,它在编码之后通过观测实际编码帧大小来决定下一帧是否需要丢弃。

5.1 漏桶模型

复制代码
  编码帧(大小 = framesize_kbits)
           │
           ▼ Fill()
   ┌───────────────┐
   │   accumulator │  ← 当前桶内积累的比特数
   │   (水桶)    │
   └───────┬───────┘
           │ Leak()
           ▼ 每帧漏出 target_bitrate/fps 比特
   
   accumulator > accumulator_max_ ?
         │是
         ▼ UpdateRatio() → 提升 drop_ratio_
         
   DropFrame() 按照 drop_ratio_ 决定下一帧是否丢弃

关键参数说明:

参数 默认值 说明
target_bitrate_ 300 kbps 目标码率
incoming_frame_rate_ 30 fps 输入帧率
accumulator_max_ target_bitrate × 0.5s 桶的容量(半秒的数据量)
kAccumulatorCapBufferSizeSecs 3.0 s 桶的最大上限(防止屏幕共享大帧引发过多丢帧)
kDefaultMaxDropDurationSecs 4.0 s 连续丢帧最大持续时间
kLargeDeltaFactor 3 超过平均帧大小 3 倍则视为"大帧"

5.2 Fill() ------ 向桶中注入数据

cpp 复制代码
void FrameDropper::Fill(size_t framesize_bytes, bool delta_frame) {
    float framesize_kbits = 8.0f * framesize_bytes / 1000.0f;
    
    if (!delta_frame) {  // I 帧(关键帧)
        // 计算分摊次数 = min(1/关键帧频率, 帧率/2)
        // 将 I 帧大小分摊到后续多帧,避免单帧过大导致突发丢帧
        large_frame_accumulation_count_ = ...;
        large_frame_accumulation_chunk_size_ = framesize_kbits / count;
        framesize_kbits = 0;  // 本帧不立即注入
    } else {  // P 帧(差异帧)
        if (framesize_kbits > kLargeDeltaFactor × 平均帧大小) {
            // 超大 P 帧(如场景切换)也做分摊处理
            ...
        } else {
            delta_frame_size_avg_kbits_.Apply(1, framesize_kbits);  // 更新平均帧大小
        }
    }
    accumulator_ += framesize_kbits;
    CapAccumulator();  // 限制桶的最大深度
}

I 帧分摊逻辑详解:

I 帧通常比 P 帧大 10-30 倍,如果直接注入桶中,会瞬间触发大量丢帧。WebRTC 的做法是将 I 帧的比特数分摊到后续 N 帧(N ≈ 1/关键帧频率,通常为 15~30 帧),每帧 Leak() 时额外少漏出一个 chunk,从而平滑处理 I 帧带来的突发。

5.3 Leak() ------ 从桶中漏出数据

cpp 复制代码
void FrameDropper::Leak(uint32_t input_framerate) {
    // 每帧应消耗的比特数
    float expected_bits_per_frame = target_bitrate_ / input_framerate;
    
    // 如果有大帧分摊,减少本帧漏出量
    if (large_frame_accumulation_count_ > 0) {
        expected_bits_per_frame -= large_frame_accumulation_chunk_size_;
        --large_frame_accumulation_count_;
    }
    
    accumulator_ -= expected_bits_per_frame;
    if (accumulator_ < 0.0f) accumulator_ = 0.0f;
    
    UpdateRatio();  // 根据桶的水位更新丢帧比例
}

5.4 UpdateRatio() ------ 动态调整丢帧比例

复制代码
accumulator > 1.3 × accumulator_max_ ?
    │是 → 快速反应(base=0.8)
    │否 → 正常反应(base=0.9)
    │
    ▼
accumulator > accumulator_max_ ?
    │是 → drop_ratio_ 增大(趋向 1.0)
    │   → 同时设置 drop_next_ = true(立即丢下一帧)
    │否 → drop_ratio_ 减小(趋向 0.0)

drop_ratio_ 是一个指数滤波值(ExpFilter),变化平滑,避免丢帧行为抖动。

5.5 DropFrame() ------ 最终丢帧决策

复制代码
drop_ratio_ >= 0.5 时(高丢帧率模式):
    limit = 1/(1 - drop_ratio_) - 1  (每保留1帧,中间丢 limit 帧)
    drop_count_ < limit → 丢帧
    drop_count_ >= limit → 保帧并重置计数

drop_ratio_ 在 (0, 0.5) 时(低丢帧率模式):
    limit = -(1/drop_ratio_ - 1)     (每丢1帧,中间保留 |limit| 帧)
    按负计数器逻辑决定丢/保

举例说明:

drop_ratio_ 丢帧模式 limit 值 效果
0.75 高丢帧率 3 丢3帧保1帧
0.5 边界 1 丢1帧保1帧
0.33 低丢帧率 -2 丢1帧保2帧
0.25 低丢帧率 -3 丢1帧保3帧
0.0 不丢帧 - 全部保留

5.6 FrameDropper 在 VideoStreamEncoder 中的调用时序

复制代码
每帧到达
    │
    ▼
MaybeEncodeVideoFrame()
    │
    ├── frame_dropper_.Leak(framerate_fps)  ← 先漏水(每帧都调用)
    │
    ├── frame_dropper_.Enable(...)          ← 控制是否启用
    │   (trusted rate controller时关闭)
    │
    └── frame_dropper_.DropFrame() ?
            │是 → 丢帧(kMediaOptimization)
            │否 → EncodeVideoFrame()

编码完成后(RunPostEncode):
    frame_dropper_.Fill(frame_size.bytes(), !keyframe)  ← 注入实际帧大小

六、第四层:资源自适应------CPU与质量触发降级

当上面三层的丢帧还不够时(比如持续高负载),WebRTC 会通过资源自适应处理器触发更根本的变化:降低分辨率或帧率。

6.1 CPU 过载检测:OveruseFrameDetector

路径:video/adaptation/overuse_frame_detector.cc

OveruseFrameDetector 监控每帧的编码时长占帧间隔的比例(即编码 CPU 使用率),通过定时任务周期性检查:

复制代码
定期调用 CheckForOveruse()
    │
    ├── encode_usage_percent_ > 85% (high_threshold)?
    │       连续 2 次超阈值? → AdaptDown()(降级)
    │
    └── encode_usage_percent_ < 42% (low_threshold)?
            满足观察期? → AdaptUp()(升级)

关键阈值表:

参数 默认值 含义
high_encode_usage_threshold_percent 85% 超过此值触发 AdaptDown
low_encode_usage_threshold_percent 42% 低于此值触发 AdaptUp
min_frame_samples 120 帧 最少需要 120 帧样本才能做判断
high_threshold_consecutive_count 2 次 连续 2 次检测到过载才触发降级
frame_timeout_interval_ms 1500 ms 超过此时间没有帧,重置统计

6.2 QP 质量监控:QualityScaler

路径:modules/video_coding/utility/quality_scaler.cc

QP(Quantization Parameter)是编码器质量的直接反映:QP 越高,压缩越猛,质量越差。QualityScaler 通过监控平均 QP 来判断是否需要降分辨率:

复制代码
每 2 秒执行一次 CheckQp()
    │
    ├── 丢帧率 >= 60%? → 报告 kHighQp(触发降分辨率)
    │
    ├── 平均 QP > high_threshold? → kHighQp
    │
    └── 平均 QP <= low_threshold? → kLowQp(触发升分辨率)

不同编码器的 QP 阈值参考(以常见编解码器为例):

编解码器 QP Low(升级阈值) QP High(降级阈值) 说明
VP8 29 95 软件编码器典型值
VP9 32 100 效率更高,QP范围更大
H264 24 37 QP范围 0~51
H265 26 39 类似 H264

6.3 降级决策:VideoStreamAdapter

路径:call/adaptation/video_stream_adapter.cc

收到 AdaptDown() 信号后,VideoStreamAdapter 根据**降级偏好(DegradationPreference)**决定具体的降级策略:

复制代码
AdaptDown() 信号到来
    │
    ▼
switch (degradation_preference_)
    │
    ├── MAINTAIN_FRAMERATE → DecreaseResolution()(只降分辨率)
    │
    ├── MAINTAIN_RESOLUTION → DecreaseFramerate()(只降帧率)
    │
    ├── BALANCED → 先尝试 DecreaseFramerate()
    │              若帧率已是最低 → DecreaseResolution()
    │
    └── DISABLED → 不做任何降级

降级偏好策略对比:

策略 降级方式 适用场景 优点 缺点
MAINTAIN_FRAMERATE 只降分辨率 视频会议 运动流畅 画面模糊
MAINTAIN_RESOLUTION 只降帧率 共享内容、PPT 清晰度高 运动卡顿
BALANCED 先降帧率再降分辨率 通用场景 均衡 行为复杂
DISABLED 不降级 特殊需求 最高质量 可能崩溃

分辨率降级步长(DecreaseResolution):

cpp 复制代码
// 每次降级,目标像素数降为当前的 3/5(约等于边长缩小到 sqrt(3/5) ≈ 0.775)
int GetLowerResolutionThan(int pixel_count) {
    return (pixel_count * 3) / 5;
}

例如:1280×720 = 921600 像素 → × 3/5 = 552960 ≈ 960×576 → × 3/5 = 331776 ≈ 640×480

帧率降级步长(DecreaseFramerate):

BALANCED 模式下,帧率降级的目标帧率由 BalancedDegradationSettings::MinFps() 查表决定,根据当前分辨率从配置表中获取最低帧率目标。

6.4 降级结果的传递链路

复制代码
VideoStreamAdapter::DecreaseResolution()
    │
    ▼ 设置 VideoSourceRestrictions
    { max_pixels_per_frame = target_pixels }
    │
    ▼
VideoStreamEncoder::OnVideoSourceRestrictionsUpdated()
    │
    ▼
VideoAdapter::OnSinkWants()
    { sink_wants.max_pixel_count = target_pixels }
    │
    ▼
下一帧进入 AdaptFrameResolution() 时生效

整个调用链实现了"上层决策、下层执行"的分层架构,每一层职责清晰。


七、所有丢帧类型汇总

WebRTC 在统计模块 SendStatisticsProxy 中对丢帧原因进行了精细的分类统计:

丢帧类型 枚举值 触发位置 触发原因
采集源丢帧 kSource VideoAdapter 帧率过高,超过目标帧率
时间戳异常 kBadTimestamp VideoStreamEncoder NTP 时间戳相同或倒退
编码队列积压 kEncoderQueue VideoStreamEncoder 新帧到达时上一帧还未编完
码率过载 kMediaOptimization FrameDropper 漏桶积累超限
拥塞窗口回退 kCongestionWindow VideoStreamEncoder 网络拥塞,cwnd 减小
编码器内部丢帧 kEncoder 编码器 编码器自身决策

八、分辨率降级触发条件汇总

触发条件 检测模块 检测周期 降级动作
CPU 编码耗时占比 > 85% OveruseFrameDetector ~5 秒 降分辨率/帧率
平均 QP > 高阈值 QualityScaler 2 秒 降分辨率/帧率
丢帧率 >= 60% QualityScaler 2 秒 降分辨率/帧率
码率 < 300kbps 且分辨率 > QVGA DropDueToSize 每帧 存入 pending_frame_,触发降级
带宽不匹配(BandwidthQualityScaler) BandwidthQualityScaler 2 秒 降分辨率/帧率

九、完整数据流总结

下面是一个完整帧的生命周期(正常场景下):

复制代码
1. 摄像头采集帧(如 1080p@30fps)
          │
          ▼
2. VideoAdapter::AdaptFrameResolution()
   → 检查帧率:是否超过 max_fps?超过则丢帧
   → 检查分辨率:根据 OnSinkWants() 的限制,计算缩放比
   → 输出裁剪/缩放后的尺寸(如 720p@15fps)
          │
          ▼
3. VideoStreamEncoder::OnIncomingFrame()
   → queue_overload / cwnd_frame_drop 检查 → 可能丢帧
   → 时间戳合法性检查 → 可能丢帧
          │
          ▼
4. MaybeEncodeVideoFrame()
   → EncoderPaused() 检查 → 可能暂存帧
   → DropDueToSize() 检查 → 可能丢帧并触发降级
   → frame_dropper_.Leak() → 漏水
   → frame_dropper_.DropFrame() → 漏桶丢帧决策
          │
          ▼
5. EncodeVideoFrame()
   → 实际调用硬件/软件编码器
   → 生成 H264/VP8/VP9 码流
          │
          ▼
6. RunPostEncode()
   → frame_dropper_.Fill(frame_size) → 向漏桶注入实际帧大小
   → OveruseFrameDetector 更新编码时长统计
   → QualityScaler 更新 QP 统计
          │
          ▼
7. [异步] 资源自适应处理器评估
   → 若持续过载 → AdaptDown() → 降低分辨率/帧率
   → 若长期空闲 → AdaptUp() → 尝试提升分辨率/帧率

十、工程实践经验与调优建议

10.1 常见问题排查

现象 可能原因 排查方法
帧率持续低于设定值 VideoAdapter 帧率控制或 FrameDropper 触发 查看 VAdapt Drop Frame 日志
分辨率突然降低 CPU/QP 触发降级 查看 Scaling down resolution 日志
视频卡顿但帧率正常 QP 过高,质量差 检查 QualityScaler 日志及 QP 值
带宽占用超过设定 FrameDropper 未启用(trusted rate controller) 确认 encoder_info 配置

10.2 关键日志关键词

  • VAdapt Drop Frame → VideoAdapter 丢帧
  • Scaling down resolution → 分辨率降级
  • Scaling down framerate → 帧率降级
  • Drop Frame: target bitrate → FrameDropper 丢帧
  • CheckForOveruse: encode usage → CPU 过载检测结果
  • Checking average QP → QP 质量检查结果
  • Dropping frame. Too large for target bitrate → DropDueToSize 触发

十一、总结

WebRTC 的视频质量自适应体系可以用一句话概括:从快到慢、从浅到深的分层保护机制

层次 模块 响应时间 影响范围
第一层(最快) cwnd 丢帧 / 队列丢帧 < 10ms 单帧
第二层 FrameDropper 漏桶 100ms 级 连续帧
第三层 VideoAdapter 帧率控制 帧间隔 持续帧率
第四层(最慢) CPU/QP 触发降分辨率 2~5 秒 全局配置

这套机制的精妙之处在于:

  1. 从轻到重:先丢单帧,实在不行再降分辨率,尽量保留视觉质量;
  2. 快慢结合:快速的丢帧机制应对瞬时波动,慢速的降级机制应对持续压力;
  3. 可逆设计:所有降级都有对应的升级路径(AdaptUp),网络好转后自动恢复;
  4. 可观测性:每种丢帧都有独立计数器和日志,方便问题排查。

理解这套体系不仅有助于调试 WebRTC 视频质量问题,也为设计其他实时音视频系统提供了优秀的参考范本。


参考源码路径:

  • modules/video_coding/utility/frame_dropper.cc
  • media/base/video_adapter.cc
  • video/video_stream_encoder.cc
  • video/adaptation/overuse_frame_detector.cc
  • modules/video_coding/utility/quality_scaler.cc
  • call/adaptation/video_stream_adapter.cc
  • video/adaptation/video_stream_encoder_resource_manager.cc
相关推荐
潜创微科技--高清音视频芯片方案开发2 小时前
高清音视频芯片方案选型指南 采集卡、无线图传、切换分配、hub芯片方案
音视频
这辈子谁会真的心疼你3 小时前
修改视频拍摄时间会被发现吗?修改视频拍摄时间的方法
python·音视频
却道天凉_好个秋3 小时前
音视频学习(九十):再谈srt协议
后端·音视频·srt
聊聊科技3 小时前
原创音乐人创作编曲伴奏新方式,清唱歌词的音频配合AI编曲软件超好用
人工智能·音视频
西***63474 小时前
藏在应急指挥车中的 “核心密码”
矩阵·音视频
tzc_fly4 小时前
VideoWorld1-2:纯视频学习获取世界知识
学习·音视频
EasyDSS4 小时前
WebRTC/语音转文字STT/AI语言大模型重构EasyDSS视频会议
音视频·webrtc·语音识别·hls·实时字幕
CrystalShaw4 小时前
WebRTC QoS方法之NetEQ在流量卡下应用的局限
webrtc
美狐美颜sdk5 小时前
实时美颜滤镜卡顿怎么办?美颜sdk滤镜特效开发优化方案
人工智能·深度学习·计算机视觉·音视频·美颜sdk·视频美颜sdk·美狐美颜sdk