webtrc 中VideoAdapter类中的作用及局限

2023-11-16

需求


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

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

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<int>::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的宽高比进行缩放

帧率的适配

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

局限

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

webtrc 中VideoAdapter类中的作用及局限 的相关文章

  • 如何获取正在访问 ASP.NET 应用程序的当前用户?

    为了获取系统中当前登录的用户 我使用以下代码 string opl System Security Principal WindowsIdentity GetCurrent Name ToString 我正在开发一个 ASP NET 应用程
  • 如何使用 C# 中的参数将用户重定向到 paypal

    如果我有像下面这样的简单表格 我可以用它来将用户重定向到 PayPal 以完成付款
  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • 为什么两个不同的 Base64 字符串的转换会返回相等的字节数组?

    我想知道为什么从 base64 字符串转换会为不同的字符串返回相同的字节数组 const string s1 dg const string s2 dq byte a1 Convert FromBase64String s1 byte a2
  • 动态加载程序集的应用程序配置

    我正在尝试将模块动态加载到我的应用程序中 但我想为每个模块指定单独的 app config 文件 假设我的主应用程序有以下 app config 设置
  • 嵌套接口:将 IDictionary> 转换为 IDictionary>?

    我认为投射一个相当简单IDictionary
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • 使用 x509 证书签署 json 文档或字符串

    如何使用 x509 证书签署 json 文档或字符串 public static void fund string filePath C Users VIKAS Desktop Data xml Read the file XmlDocum
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • 如何使用 C# / .Net 将文件列表从 AWS S3 下载到我的设备?

    我希望下载存储在 S3 中的多个图像 但目前如果我只能下载一个就足够了 我有对象路径的信息 当我运行以下代码时 出现此错误 遇到错误 消息 读取对象时 访问被拒绝 我首先做一个亚马逊S3客户端基于我的密钥和访问配置的对象连接到服务器 然后创
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • IEnumreable 动态和 lambda

    我想在 a 上使用 lambda 表达式IEnumerable
  • 如何将服务器服务连接到 Dynamics Online

    我正在修改内部管理应用程序以连接到我们的在线托管 Dynamics 2016 实例 根据一些在线教程 我一直在使用OrganizationServiceProxy out of Microsoft Xrm Sdk Client来自 SDK
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现
  • 如何在文本框中插入图像

    有没有办法在文本框中插入图像 我正在开发一个聊天应用程序 我想用图标图像更改值 等 但我找不到如何在文本框中插入图像 Thanks 如果您使用 RichTextBox 进行聊天 请查看Paste http msdn microsoft co
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new

随机推荐

  • Redis事务、持久化、发布订阅

    文章目录 Redis事务 Redis持久化 RDB Redis DataBase 快照方式 AOF Append Only File 日志形式 Redis发布订阅 发布订阅模型 实例 Redis发布订阅命令 原理 Redis事务 Redis
  • flutter 字符串的常用属性及方法

    1 字符串长度 var str 字符串的长度 print 打印 str length 打印 6 var str1 hello dart print 打印 str1 length 打印 10 2 是否为空 str isEmpty为空true
  • 关于ElasticSearch的Update By Query的那些著名的坑

    提起es的Update By Query很多人一定也不陌生 它对应的就是关系型数据库的update set where 语句 这对应一般的存储引擎而言算是最基本的功能 但它的坑确不少 多到让你使用起来很奔溃 比如批量更新时非事务模式执行 允
  • selenium自动化测试的问题解决及优化

    目录 一 安装出现的问题 1 webdriver has no attribute find element by id 2 gecodriver needs to be in PATH 3 安装了selenium报错has no attr
  • io第一天

    ubuntu ubuntu day1 c cat 8 c include
  • PL/SQL 导入SQL文件时报“Error reading file”

    从另一台机器上导出了一个表的数据 有2万多条 导出的sql文件大小将近40M 之后使用PL SQL的Command Window窗口执行sql文件 执行命令是 SQL文件全路径 提示错误 Error reading file不知道是不是因为
  • 在Ubuntu中安装中文输入法

    文章目录 前言 基础准备 ibus Intelligent Input Bus fcitx Flexible Input Method Framework 前言 Ubuntu中安装中文输入法相比Windows上要复杂不少 其实也不算复杂 就
  • js实现一个表单输入验证,重复字符验证

    logon password check 加班到现在 还是得发个 csdn 本文主要通过一个案例介绍两个东西 正则表达式中 必须含有某类字符的时候对应的 正则写法 在我之前的正则文章中已经写过了 重复字符以及连续字符的判断方式 正则来表示验
  • JavaScript window.location对象

    http www cnblogs com ljan archive 2012 02 27 2369960 html location 地址对象 它描述的是某一个窗口对象所打开的地址 要表示当前窗口的地址 只需要使用 location 就行了
  • nodejs html引用js_nodejs做出最简单的网页服务端。【501】

    一 先去官网下载nodejs 按自己的系统一步一步操作 基本很简单 这里就不多介绍了 二 安装完成后 通过cmd验证是否安装成功 输入node v可以查看版本号 三 用开发工具创建一个js文件 命名为server js 四 开始写js文件
  • Hadoop环境搭建及常见问题解决(保姆级教程)

    Hadoop环境搭建及常见问题解决 零 资源准备 一 环境准备 1 安装虚拟机 2 环境准备 1 创建新用户xiaobai 2 安装ssh server 3 上传相关资源 4 使用putty连接服务器 5 设置主机名 6 检查和关闭防火墙
  • windows信息收集自动化脚本

    import os encoding utf 8 class information collecting object def init self self system info commands windows版本信息 n ver w
  • prbs码

    prbs7 111110110011100001101010010001011111110000001000001100001010001111001000101100111010100111110100001110001001001101
  • .Net传值方式主要有以下几种

    1 url传值 如 CheckPwd aspx user uservalue pwd pwdvalue 2 Session传值 如 Session role Administrator 3 Viewstate role Administra
  • Selenium+PhantomJS使用时报错原因及解决方案

    问题 今天在使用selenium PhantomJS动态抓取网页时 出现如下报错信息 UserWarning Selenium support for PhantomJS has been deprecated please use hea
  • 异常处理UncaughtExceptionHandler

    自动捕获未知异常的主要思路是 在Application注册一个实现了UncaughtExceptionHandler的对象 然后在该对象中调用方法Thread setDefaultUncaughtExceptionHandler设置未知异常
  • [一步一步学react系列] 03—计数器V1.0

    前言 在上文中我们学习了react的工作流程 知道了用户点击操作先是分发action 然后reducer根据接收到的action来做具体值的改变的这个曲折过程 仔细看redux工作流的盆友一定发现了 上文中并没有用到最中心的store 那么
  • C语言基础-08 字符数组、字符串

    目录 一 定义字符数组 二 字符数组的初始化 三 字符串和字符串结束标志 四 字符数组的输入输出 五 使用字符串处理函数 1 输出字符串的函数 2 输入字符串的数组 六 数组中常用的字符串函数 1 strlen 2 strcat strnc
  • Java:注意事项集合

    回车与换行的区别 CRLF CR LF详解 r n r n的区别 https blog csdn net lishuoboy article details 84768748 java中String的格式化format 方法https bl
  • webtrc 中VideoAdapter类中的作用及局限

    需求 文章目录 需求 VideoAdapter类 分辨率的适配 帧率的适配 局限 在媒体库中 是要求能动态改变编码的分辨率和帧率的 思路是重启编码器 设置编码器新的分辨率 帧率参数来满足要求 所以输入到编码器中的视频流分辨率 帧率应该与设置