当前位置:网站首页>webtrc 中VideoAdapter类中的作用及局限
webtrc 中VideoAdapter类中的作用及局限
2022-08-04 05:25:00 【mo4776】
需求
在媒体库中,是要求能动态改变编码的分辨率和帧率的,思路是重启编码器,设置编码器新的分辨率,帧率参数来满足要求。所以输入到编码器中的视频流分辨率,帧率应该与设置的分辨率参数是一致的。
但是不能通过改变视频采集的分辨率来实现,否则可能会造成摄像头重启,导致图像会黑一下。往往是在送入编码器之前应该有专门进行分辨率,码率适配的功能类。输入的是视频采集的原始分辨率和帧率,输出的是满足于编码器的编码分辨率和帧率。
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
来决定最佳比例,有两点注意:
- 宽,高各自按比例缩小
- 并不改变原始的宽宽比,比如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
进行改造,使它能支持指定分辨率的放大,缩小。
边栏推荐
猜你喜欢
随机推荐
The idea setting recognizes the .sql file type and other file types
Summary of MySQL database interview questions (2022 latest version)
9. Dynamic SQL
7、特殊SQL的执行
程序员也应了解的Unity粒子系统
Performance testing with Loadrunner
php实现telnet访问端口
MySql data recovery method personal summary
符号表
Swoole学习(一)
Deploy LVS-DR cluster [experimental]
sql server如何得到本条记录与上一条记录的差异,即变动值
Cannot read properties of null (reading 'insertBefore')
Gartner 权威预测未来4年网络安全的8大发展趋势
PHP实现异步执行程序
MySQL database (basic)
EntityComponentSystemSamples学习笔记
MySQL数据库(基础)
string类简介
OpenRefine中的正则表达式