WebRTC中VideoAdapter类中的作用及局限

需求

在媒体库中,是要求能动态改变编码的分辨率和帧率的,思路是重启编码器,设置编码器新的分辨率,帧率参数来满足要求。所以输入到编码器中的视频流分辨率,帧率应该与设置的分辨率参数是一致的。

但是不能通过改变视频采集的分辨率来实现,否则可能会造成摄像头重启,导致图像会黑一下。往往是在送入编码器之前应该有专门进行分辨率,码率适配的功能类。输入的是视频采集的原始分辨率和帧率,输出的是满足于编码器的编码分辨率和帧率。

C++音视频开发WebRTC学习资料点击领取音视频开发(资料文档+视频教程+面试题)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)

VideoAdapter类

分辨率的适配

webrtc中VideoAdapter类就是实现这里的功能的,决定缩放比例的核心函数FindScale

Fraction FindScale(int input_width,
                   int input_height,
                   int target_pixels,
                   int max_pixels,
                   bool variable_start_scale_factor) {
  // This function only makes sense for a positive target.
  RTC_DCHECK_GT(target_pixels, 0);
  RTC_DCHECK_GT(max_pixels, 0);
  RTC_DCHECK_GE(max_pixels, target_pixels);

  const int input_pixels = input_width * input_height;

  // Don't scale up original.
  if (target_pixels >= input_pixels)
    return Fraction{1, 1};

  Fraction current_scale = Fraction{1, 1};
  Fraction best_scale = Fraction{1, 1};

  if (variable_start_scale_factor) {
    // Start scaling down by 2/3 depending on |input_width| and |input_height|.
    if (input_width % 3 == 0 && input_height % 3 == 0) {
      // 2/3 (then alternates 3/4, 2/3, 3/4,...).
      current_scale = Fraction{6, 6};
    }
    if (input_width % 9 == 0 && input_height % 9 == 0) {
      // 2/3, 2/3 (then alternates 3/4, 2/3, 3/4,...).
      current_scale = Fraction{36, 36};
    }
  }

  // The minimum (absolute) difference between the number of output pixels and
  // the target pixel count.
  int min_pixel_diff = std::numeric_limits::max();
  if (input_pixels <= max_pixels) {
    // Start condition for 1/1 case, if it is less than max.
    min_pixel_diff = std::abs(input_pixels - target_pixels);
  }
  
  //720p为16:9,宽高各自缩放对应的比率,宽高比率还是16:9
  //宽,高各自按比例计算,算法会依次取3/4,1/2,3/8,1/4,3/16,1/8进行计算,选择一个适合的分辨率
  // Alternately scale down by 3/4 and 2/3. This results in fractions which are
  // effectively scalable. For instance, starting at 1280x720 will result in
  // the series (3/4) => 960x540, (1/2) => 640x360, (3/8) => 480x270,
  // (1/4) => 320x180, (3/16) => 240x125, (1/8) => 160x90.
  while (current_scale.scale_pixel_count(input_pixels) > target_pixels) {
    if (current_scale.numerator % 3 == 0 &&
        current_scale.denominator % 2 == 0) {
      // Multiply by 2/3.乘以 2/3
      current_scale.numerator /= 3;
      current_scale.denominator /= 2;
    } else {
      // Multiply by 3/4.乘以 3/4
      current_scale.numerator *= 3;
      current_scale.denominator *= 4;
    }
    
    //根本宽,高的比例计算像素
    int output_pixels = current_scale.scale_pixel_count(input_pixels);
    if (output_pixels <= max_pixels) {
      int diff = std::abs(target_pixels - output_pixels);
      if (diff < min_pixel_diff) {
        min_pixel_diff = diff;
        best_scale = current_scale;
      }
    }
  }
  best_scale.DivideByGcd();

  return best_scale;
}

辅助类Fraction,表示分数

struct Fraction {
  //分子
  int numerator;
  //分母
  int denominator;

  void DivideByGcd() {
    //获取最大公约数
    int g = cricket::GreatestCommonDivisor(numerator, denominator);
    numerator /= g;
    denominator /= g;
  }

  // Determines number of output pixels if both width and height of an input of
  // |input_pixels| pixels is scaled with the fraction numerator / denominator.
  int scale_pixel_count(int input_pixels) {
    //宽,高各自按比例计算,计算总像素数
    return (numerator * numerator * input_pixels) / (denominator * denominator);
  }
};
  • 计算最大公约数
int GreatestCommonDivisor(int a, int b) {
  RTC_DCHECK_GE(a, 0);
  RTC_DCHECK_GT(b, 0);
  int c = a % b;
  while (c != 0) {
    a = b;
    b = c;
    c = a % b;
  }
  return b;
}

VideoAdapter并不支持放大,只能缩小。主要功能在FindScale中实现,它的功能是根据targer_pixel_count来决定最佳比例,有两点注意:

  1. 宽,高各自按比例缩小
  2. 并不改变原始的宽宽比,比如720P(1280*720,16:9),是按16:9的宽高比进行缩放

C++音视频开发WebRTC学习资料点击领取音视频开发(资料文档+视频教程+面试题)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)

帧率的适配

帧率的是适配也是只能从大到小,核心功能在VideoAdpater类的KeepFrame方法,实现思路比较简单根据目标帧率来计算时间间隔,再根据时间间隔来采取丢帧的策略来达到目的帧率

局限

webrtc中分辨率的动态改变,是webrtc中内部决策的,可能影响分辨率改变的是网络环境,机器性能等,对外部业务来说也是个黑盒子。并且分辨率的变化是保持宽高比的,比如采集的分辨率为720P(16:9),需要变为VGA(640 * 480->4:3),在webrtc而是缩放成最解决这个分辨率,宽高比为16:9的值,为640 * 360。

很多场景和业务对媒体库支持动态改变分辨率范围是有要求的,比如要是支持720P,VGA,CIF这样范围并且能相互变换,显然它们的宽高比是不一致的,VideoAdpater现有逻辑是无法满足这样的要求的。所以媒体库中会对VideoAapter进行改造,使它能支持指定分辨率的放大,缩小。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章