no message
parent
96726fec7e
commit
8ee95a6c7b
|
@ -1,434 +0,0 @@
|
||||||
#include "CPlayWidget.h"
|
|
||||||
|
|
||||||
#include <QOpenGLTexture>
|
|
||||||
#include <QOpenGLBuffer>
|
|
||||||
#include <QMouseEvent>
|
|
||||||
#include "CPlayWidget.h"
|
|
||||||
|
|
||||||
|
|
||||||
// 顶点着色器源码
|
|
||||||
|
|
||||||
const char *vsrcyuv = "attribute vec4 vertexIn; \
|
|
||||||
attribute vec2 textureIn; \
|
|
||||||
varying vec2 textureOut; \
|
|
||||||
void main(void) \
|
|
||||||
{ \
|
|
||||||
gl_Position = vertexIn; \
|
|
||||||
textureOut = textureIn; \
|
|
||||||
}";
|
|
||||||
|
|
||||||
|
|
||||||
// 片段着色器源码
|
|
||||||
|
|
||||||
const char *fsrcyuv = "varying vec2 textureOut; \
|
|
||||||
uniform sampler2D tex_y; \
|
|
||||||
uniform sampler2D tex_u; \
|
|
||||||
uniform sampler2D tex_v; \
|
|
||||||
void main(void) \
|
|
||||||
{ \
|
|
||||||
vec3 yuv; \
|
|
||||||
vec3 rgb; \
|
|
||||||
yuv.x = texture2D(tex_y, textureOut).r; \
|
|
||||||
yuv.y = texture2D(tex_u, textureOut).r - 0.5; \
|
|
||||||
yuv.z = texture2D(tex_v, textureOut).r - 0.5; \
|
|
||||||
rgb = mat3( 1, 1, 1, \
|
|
||||||
0, -0.39465, 2.03211, \
|
|
||||||
1.13983, -0.58060, 0) * yuv; \
|
|
||||||
gl_FragColor = vec4(rgb, 1); \
|
|
||||||
}";
|
|
||||||
|
|
||||||
// rgb片段着色器源码
|
|
||||||
// 注意MEDIASUBTYPE_RGB32 是bgr的,所以需要再进行一次转换
|
|
||||||
|
|
||||||
|
|
||||||
const char *fsrcrgb = "varying vec2 textureOut; \
|
|
||||||
uniform sampler2D rgbdata; \
|
|
||||||
void main() \
|
|
||||||
{ \
|
|
||||||
gl_FragColor = texture(rgbdata, textureOut); \
|
|
||||||
}";
|
|
||||||
|
|
||||||
void CPlayWidget::OnUpdateFrame() {
|
|
||||||
this->PlayOneFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPlayWidget::OnPaintData(const uint8_t *data, uint32_t len)
|
|
||||||
{
|
|
||||||
if(nullptr == m_pBufYuv420p)
|
|
||||||
{
|
|
||||||
m_pBufYuv420p = new unsigned char[len];
|
|
||||||
qDebug("CPlayWidget::PlayOneFrame new data memory. Len=%d width=%d height=%d\n",
|
|
||||||
len, m_nVideoW, m_nVideoW);
|
|
||||||
memcpy(m_pBufYuv420p, data,len);
|
|
||||||
//刷新界面,触发paintGL接口
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CPlayWidget::CPlayWidget(QWidget *parent):QOpenGLWidget(parent) {
|
|
||||||
textureUniformY = 0;
|
|
||||||
textureUniformU = 0;
|
|
||||||
textureUniformV = 0;
|
|
||||||
id_y = 0;
|
|
||||||
id_u = 0;
|
|
||||||
id_v = 0;
|
|
||||||
m_pTextureRGB = nullptr;
|
|
||||||
m_pBufYuv420p = nullptr;
|
|
||||||
m_pVSHader = NULL;
|
|
||||||
m_pFSHader = NULL;
|
|
||||||
m_pShaderProgram = NULL;
|
|
||||||
m_pTextureY = NULL;
|
|
||||||
m_pTextureU = NULL;
|
|
||||||
m_pTextureV = NULL;
|
|
||||||
m_pYuvFile = NULL;
|
|
||||||
m_nVideoH = 0;
|
|
||||||
m_nVideoW = 0;
|
|
||||||
mType = TYPE_YUV420P;
|
|
||||||
connect(&this->tm,SIGNAL(timeout()),this,SLOT(OnUpdateFrame()));
|
|
||||||
//tm.start(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
CPlayWidget::~CPlayWidget() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPlayWidget::PlayOneFrame() {//函数功能读取一张yuv图像数据进行显示,每单击一次,就显示一张图片
|
|
||||||
if(NULL == m_pYuvFile)
|
|
||||||
{
|
|
||||||
//打开yuv视频文件 注意修改文件路径
|
|
||||||
// m_pYuvFile = fopen("F://OpenglYuvDemo//1920_1080.yuv", "rb");
|
|
||||||
m_pYuvFile = fopen("F://md_sample_sp420_1080p.yuv", "rb");
|
|
||||||
//根据yuv视频数据的分辨率设置宽高,demo当中是1080p,这个地方要注意跟实际数据分辨率对应上
|
|
||||||
// m_nVideoW = 1920;
|
|
||||||
// m_nVideoH = 1080;
|
|
||||||
}
|
|
||||||
//申请内存存一帧yuv图像数据,其大小为分辨率的1.5倍
|
|
||||||
|
|
||||||
|
|
||||||
int nLen = m_nVideoW*m_nVideoH*3/2;
|
|
||||||
if(nullptr == m_pBufYuv420p)
|
|
||||||
{
|
|
||||||
m_pBufYuv420p = new unsigned char[nLen];
|
|
||||||
qDebug("CPlayWidget::PlayOneFrame new data memory. Len=%d width=%d height=%d\n",
|
|
||||||
nLen, m_nVideoW, m_nVideoW);
|
|
||||||
}
|
|
||||||
//将一帧yuv图像读到内存中
|
|
||||||
|
|
||||||
if(NULL == m_pYuvFile)
|
|
||||||
{
|
|
||||||
qFatal("read yuv file err.may be path is wrong!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fread(m_pBufYuv420p, 1, nLen, m_pYuvFile);
|
|
||||||
//刷新界面,触发paintGL接口
|
|
||||||
update();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CPlayWidget::SetDataType(CPlayWidget::IMG_TYPE type){
|
|
||||||
this->mType = type;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CPlayWidget::OnCameraData(uint8_t *dat, uint32_t size)
|
|
||||||
{
|
|
||||||
if(nullptr == m_pBufYuv420p)
|
|
||||||
{
|
|
||||||
m_pBufYuv420p = new unsigned char[size];
|
|
||||||
qDebug("CPlayWidget::PlayOneFrame new data memory. Len=%d width=%d height=%d\n",
|
|
||||||
size, m_nVideoW, m_nVideoW);
|
|
||||||
memcpy(m_pBufYuv420p, dat,size);
|
|
||||||
//刷新界面,触发paintGL接口
|
|
||||||
update();
|
|
||||||
}else{
|
|
||||||
memcpy(m_pBufYuv420p, dat,size);
|
|
||||||
update();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int CPlayWidget::SetImgSize(uint32_t width, uint32_t height)
|
|
||||||
{
|
|
||||||
m_nVideoH = height;
|
|
||||||
m_nVideoW = width;
|
|
||||||
if(mType == TYPE_RGB32){
|
|
||||||
m_pBufRgb32 = new uint8_t[width * height *4];
|
|
||||||
}
|
|
||||||
if(mType == TYPE_YUV420P){
|
|
||||||
m_pBufYuv420p = new uint8_t[width * height *3/2];
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
* Y = 0.299 R + 0.587 G + 0.114 B
|
|
||||||
|
|
||||||
U = - 0.1687 R - 0.3313 G + 0.5 B + 128
|
|
||||||
|
|
||||||
V = 0.5 R - 0.4187 G - 0.0813 B + 128
|
|
||||||
|
|
||||||
反过来,RGB 也可以直接从YUV (256级别) 计算:
|
|
||||||
|
|
||||||
R = Y + 1.402 (Cr-128)
|
|
||||||
|
|
||||||
G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
|
|
||||||
|
|
||||||
B = Y + 1.772 (Cb-128)
|
|
||||||
*/
|
|
||||||
void CPlayWidget::initializeGL()
|
|
||||||
{
|
|
||||||
initializeOpenGLFunctions();
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
|
|
||||||
//现代opengl渲染管线依赖着色器来处理传入的数据
|
|
||||||
//着色器:就是使用openGL着色语言(OpenGL Shading Language, GLSL)编写的一个小函数,
|
|
||||||
// GLSL是构成所有OpenGL着色器的语言,具体的GLSL语言的语法需要读者查找相关资料
|
|
||||||
//初始化顶点着色器 对象
|
|
||||||
|
|
||||||
m_pVSHader = new QOpenGLShader(QOpenGLShader::Vertex, this);
|
|
||||||
|
|
||||||
//编译顶点着色器程序
|
|
||||||
bool bCompile = m_pVSHader->compileSourceCode(vsrcyuv);
|
|
||||||
if(!bCompile)
|
|
||||||
{
|
|
||||||
// todo 设置错误状态
|
|
||||||
}
|
|
||||||
//初始化片段着色器 功能gpu中yuv转换成rgb
|
|
||||||
m_pFSHader = new QOpenGLShader(QOpenGLShader::Fragment, this);
|
|
||||||
if(mType == TYPE_RGB32){
|
|
||||||
bCompile = m_pFSHader->compileSourceCode(fsrcrgb);
|
|
||||||
}
|
|
||||||
if(mType == TYPE_YUV420P){
|
|
||||||
bCompile = m_pFSHader->compileSourceCode(fsrcyuv);
|
|
||||||
}
|
|
||||||
if(!bCompile)
|
|
||||||
{
|
|
||||||
// todo 设置错误状态
|
|
||||||
}
|
|
||||||
#define PROGRAM_VERTEX_ATTRIBUTE 0
|
|
||||||
#define PROGRAM_TEXCOORD_ATTRIBUTE 1
|
|
||||||
//创建着色器程序容器
|
|
||||||
|
|
||||||
m_pShaderProgram = new QOpenGLShaderProgram;
|
|
||||||
//将片段着色器添加到程序容器
|
|
||||||
|
|
||||||
m_pShaderProgram->addShader(m_pFSHader);
|
|
||||||
//将顶点着色器添加到程序容器
|
|
||||||
|
|
||||||
m_pShaderProgram->addShader(m_pVSHader);
|
|
||||||
//绑定属性vertexIn到指定位置ATTRIB_VERTEX,该属性在顶点着色源码其中有声明
|
|
||||||
|
|
||||||
m_pShaderProgram->bindAttributeLocation("vertexIn", ATTRIB_VERTEX);
|
|
||||||
//绑定属性textureIn到指定位置ATTRIB_TEXTURE,该属性在顶点着色源码其中有声明
|
|
||||||
|
|
||||||
m_pShaderProgram->bindAttributeLocation("textureIn", ATTRIB_TEXTURE);
|
|
||||||
//链接所有所有添入到的着色器程序
|
|
||||||
|
|
||||||
m_pShaderProgram->link();
|
|
||||||
|
|
||||||
//激活所有链接
|
|
||||||
|
|
||||||
m_pShaderProgram->bind();
|
|
||||||
|
|
||||||
if(this->mType == TYPE_YUV420P){
|
|
||||||
initShaderYuv();
|
|
||||||
}
|
|
||||||
if(this->mType == TYPE_RGB32){
|
|
||||||
initShaderRgb();
|
|
||||||
}
|
|
||||||
glClearColor(0.0,0.0,0.0,0.0);//设置背景色
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CPlayWidget::resizeGL(int w, int h)
|
|
||||||
{
|
|
||||||
if(h == 0)// 防止被零除
|
|
||||||
{
|
|
||||||
h = 1;// 将高设为1
|
|
||||||
}
|
|
||||||
//设置视口
|
|
||||||
glViewport(0,0, w,h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPlayWidget::paintGL()
|
|
||||||
{
|
|
||||||
if(mType == TYPE_YUV420P)
|
|
||||||
loadYuvTexture();
|
|
||||||
if(mType == TYPE_RGB32){
|
|
||||||
loadRgbTexture();
|
|
||||||
}
|
|
||||||
//使用顶点数组方式绘制图形
|
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPlayWidget::initShaderYuv()
|
|
||||||
{
|
|
||||||
//读取着色器中的数据变量tex_y, tex_u, tex_v的位置,这些变量的声明可以在
|
|
||||||
//片段着色器源码中可以看到
|
|
||||||
textureUniformY = m_pShaderProgram->uniformLocation("tex_y");
|
|
||||||
textureUniformU = m_pShaderProgram->uniformLocation("tex_u");
|
|
||||||
textureUniformV = m_pShaderProgram->uniformLocation("tex_v");
|
|
||||||
// 顶点矩阵
|
|
||||||
static const GLfloat vertexVertices[] = {
|
|
||||||
-1.0f, -1.0f,
|
|
||||||
1.0f, -1.0f,
|
|
||||||
-1.0f, 1.0f,
|
|
||||||
1.0f, 1.0f,
|
|
||||||
};
|
|
||||||
//纹理矩阵
|
|
||||||
static const GLfloat textureVertices[] = {
|
|
||||||
0.0f, 1.0f,
|
|
||||||
1.0f, 1.0f,
|
|
||||||
0.0f, 0.0f,
|
|
||||||
1.0f, 0.0f,
|
|
||||||
};
|
|
||||||
//设置属性ATTRIB_VERTEX的顶点矩阵值以及格式
|
|
||||||
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertexVertices);
|
|
||||||
//设置属性ATTRIB_TEXTURE的纹理矩阵值以及格式
|
|
||||||
glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, textureVertices);
|
|
||||||
//启用ATTRIB_VERTEX属性的数据,默认是关闭的
|
|
||||||
glEnableVertexAttribArray(ATTRIB_VERTEX);
|
|
||||||
//启用ATTRIB_TEXTURE属性的数据,默认是关闭的
|
|
||||||
glEnableVertexAttribArray(ATTRIB_TEXTURE);
|
|
||||||
//分别创建y,u,v纹理对象
|
|
||||||
m_pTextureY = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|
||||||
m_pTextureU = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|
||||||
m_pTextureV = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|
||||||
m_pTextureY->create();
|
|
||||||
m_pTextureU->create();
|
|
||||||
m_pTextureV->create();
|
|
||||||
//获取返回y分量的纹理索引值
|
|
||||||
id_y = m_pTextureY->textureId();
|
|
||||||
//获取返回u分量的纹理索引值
|
|
||||||
id_u = m_pTextureU->textureId();
|
|
||||||
//获取返回v分量的纹理索引值
|
|
||||||
id_v = m_pTextureV->textureId();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPlayWidget::initShaderRgb()
|
|
||||||
{
|
|
||||||
//读取着色器中的数据变量tex_y, tex_u, tex_v的位置,这些变量的声明可以在
|
|
||||||
//片段着色器源码中可以看到
|
|
||||||
textureUniformRGB = m_pShaderProgram->uniformLocation("rgbdata");
|
|
||||||
// 顶点矩阵
|
|
||||||
static const GLfloat vertexVertices[] = {
|
|
||||||
-1.0f, -1.0f,
|
|
||||||
1.0f, -1.0f,
|
|
||||||
-1.0f, 1.0f,
|
|
||||||
1.0f, 1.0f,
|
|
||||||
};
|
|
||||||
|
|
||||||
//纹理矩阵
|
|
||||||
|
|
||||||
static const GLfloat textureVertices[] = {
|
|
||||||
0.0f, 0.0f,
|
|
||||||
1.0f, 0.0f,
|
|
||||||
0.0f, 1.0f,
|
|
||||||
1.0f, 1.0f,
|
|
||||||
};
|
|
||||||
//设置属性ATTRIB_VERTEX的顶点矩阵值以及格式
|
|
||||||
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertexVertices);
|
|
||||||
//设置属性ATTRIB_TEXTURE的纹理矩阵值以及格式
|
|
||||||
glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, textureVertices);
|
|
||||||
//启用ATTRIB_VERTEX属性的数据,默认是关闭的
|
|
||||||
glEnableVertexAttribArray(ATTRIB_VERTEX);
|
|
||||||
//启用ATTRIB_TEXTURE属性的数据,默认是关闭的
|
|
||||||
glEnableVertexAttribArray(ATTRIB_TEXTURE);
|
|
||||||
//分别创建y,u,v纹理对象
|
|
||||||
m_pTextureRGB = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|
||||||
m_pTextureRGB->create();
|
|
||||||
//获取返回y分量的纹理索引值
|
|
||||||
id_rgb = m_pTextureRGB->textureId();
|
|
||||||
}
|
|
||||||
|
|
||||||
int CPlayWidget::loadYuvTexture()
|
|
||||||
{
|
|
||||||
//加载y数据纹理
|
|
||||||
//激活纹理单元GL_TEXTURE0
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
//使用来自y数据生成纹理
|
|
||||||
glBindTexture(GL_TEXTURE_2D, id_y);
|
|
||||||
//使用内存中m_pBufYuv420p数据创建真正的y数据纹理
|
|
||||||
glTexImage2D(GL_TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
GL_RED,
|
|
||||||
m_nVideoW,
|
|
||||||
m_nVideoH,
|
|
||||||
0,
|
|
||||||
GL_RED,
|
|
||||||
GL_UNSIGNED_BYTE,
|
|
||||||
m_pBufYuv420p);
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
//加载u数据纹理
|
|
||||||
glActiveTexture(GL_TEXTURE1);//激活纹理单元GL_TEXTURE1
|
|
||||||
glBindTexture(GL_TEXTURE_2D, id_u);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D,
|
|
||||||
0, GL_RED,
|
|
||||||
m_nVideoW/2,
|
|
||||||
m_nVideoH/2,
|
|
||||||
0,
|
|
||||||
GL_RED,
|
|
||||||
GL_UNSIGNED_BYTE,
|
|
||||||
(char*)m_pBufYuv420p+m_nVideoW*m_nVideoH);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
//加载v数据纹理
|
|
||||||
glActiveTexture(GL_TEXTURE2);//激活纹理单元GL_TEXTURE2
|
|
||||||
glBindTexture(GL_TEXTURE_2D, id_v);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D,
|
|
||||||
0, GL_RED,
|
|
||||||
m_nVideoW/2,
|
|
||||||
m_nVideoH/2,
|
|
||||||
0, GL_RED,
|
|
||||||
GL_UNSIGNED_BYTE,
|
|
||||||
(char*)m_pBufYuv420p+m_nVideoW*m_nVideoH*5/4);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
//指定y纹理要使用新值 只能用0,1,2等表示纹理单元的索引,这是opengl不人性化的地方
|
|
||||||
//0对应纹理单元GL_TEXTURE0 1对应纹理单元GL_TEXTURE1 2对应纹理的单元
|
|
||||||
glUniform1i(textureUniformY, 0);
|
|
||||||
//指定u纹理要使用新值
|
|
||||||
glUniform1i(textureUniformU, 1);
|
|
||||||
//指定v纹理要使用新值
|
|
||||||
glUniform1i(textureUniformV, 2);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CPlayWidget::loadRgbTexture()
|
|
||||||
{
|
|
||||||
//加载rgb数据纹理
|
|
||||||
//激活纹理单元GL_TEXTURE0
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
//使用来自y数据生成纹理
|
|
||||||
glBindTexture(GL_TEXTURE_2D, id_rgb);
|
|
||||||
//使用内存中m_pBufYuv420p数据创建真正的y数据纹理
|
|
||||||
glTexImage2D(GL_TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
GL_RGBA,
|
|
||||||
m_nVideoW,
|
|
||||||
m_nVideoH,
|
|
||||||
0,
|
|
||||||
GL_BGRA,
|
|
||||||
GL_UNSIGNED_BYTE,
|
|
||||||
m_pBufRgb32);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
glUniform1i(textureUniformRGB, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
#ifndef GLPLAYWIDGET_H
|
|
||||||
#define GLPLAYWIDGET_H
|
|
||||||
#include <QOpenGLWidget>
|
|
||||||
#include <QOpenGLShaderProgram>
|
|
||||||
#include <QOpenGLFunctions>
|
|
||||||
#include <QOpenGLTexture>
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
|
|
||||||
#include <QTimer>
|
|
||||||
#define ATTRIB_VERTEX 3
|
|
||||||
#define ATTRIB_TEXTURE 4
|
|
||||||
|
|
||||||
|
|
||||||
class CPlayWidget:public QOpenGLWidget,protected QOpenGLFunctions
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public slots:
|
|
||||||
void OnUpdateFrame();
|
|
||||||
void OnPaintData(const uint8_t *data,uint32_t len);
|
|
||||||
public:
|
|
||||||
typedef enum{
|
|
||||||
TYPE_YUV420P,
|
|
||||||
TYPE_RGB32,
|
|
||||||
}IMG_TYPE;
|
|
||||||
CPlayWidget(QWidget* parent);
|
|
||||||
~CPlayWidget();
|
|
||||||
void PlayOneFrame();
|
|
||||||
int SetDataType(IMG_TYPE);
|
|
||||||
int OnCameraData(uint8_t *dat, uint32_t size) ;
|
|
||||||
int SetImgSize(uint32_t width,uint32_t );
|
|
||||||
protected:
|
|
||||||
QTimer tm;
|
|
||||||
void initializeGL() override;
|
|
||||||
void resizeGL(int w, int h) override;
|
|
||||||
void paintGL() override;
|
|
||||||
private:
|
|
||||||
IMG_TYPE mType; // 目前只支持到RGB32,YUV420P
|
|
||||||
GLuint textureUniformY; //y纹理数据位置
|
|
||||||
GLuint textureUniformU; //u纹理数据位置
|
|
||||||
GLuint textureUniformV; //v纹理数据位置
|
|
||||||
GLuint textureUniformRGB; //RGB纹理位置
|
|
||||||
|
|
||||||
|
|
||||||
GLuint textureUnifromRGB; //rgb32 的纹理位置
|
|
||||||
|
|
||||||
GLuint id_rgb;
|
|
||||||
GLuint id_y;
|
|
||||||
GLuint id_u;
|
|
||||||
GLuint id_v; //v纹理对象ID
|
|
||||||
|
|
||||||
QOpenGLTexture* m_pTextureRGB; //RGB 纹理是一整块的
|
|
||||||
|
|
||||||
QOpenGLTexture* m_pTextureY; //y纹理对象
|
|
||||||
QOpenGLTexture* m_pTextureU; //u纹理对象
|
|
||||||
QOpenGLTexture* m_pTextureV; //v纹理对象
|
|
||||||
QOpenGLShader *m_pVSHader; //顶点着色器程序对象
|
|
||||||
QOpenGLShader *m_pFSHader; //片段着色器对象
|
|
||||||
QOpenGLShaderProgram *m_pShaderProgram; //着色器程序容器
|
|
||||||
int m_nVideoW; //视频分辨率宽
|
|
||||||
int m_nVideoH; //视频分辨率高
|
|
||||||
unsigned char *m_pBufYuv420p;
|
|
||||||
unsigned char* m_pBufRgb32;
|
|
||||||
|
|
||||||
FILE* m_pYuvFile;
|
|
||||||
|
|
||||||
void initShaderYuv();
|
|
||||||
void initShaderRgb();
|
|
||||||
|
|
||||||
int loadYuvTexture();
|
|
||||||
int loadRgbTexture();
|
|
||||||
};
|
|
||||||
#endif
|
|
|
@ -1,82 +0,0 @@
|
||||||
#include "mainwindow.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
|
|
||||||
#include "modules/video_capture/video_capture.h"
|
|
||||||
#include "video_capturer_test.h"
|
|
||||||
#include <QString>
|
|
||||||
#include <QDebug>
|
|
||||||
#include "modules/video_capture/video_capture_factory.h"
|
|
||||||
#include "rtc_base/logging.h"
|
|
||||||
#include "video_capture.h"
|
|
||||||
#include "video_capturer_test.h"
|
|
||||||
|
|
||||||
|
|
||||||
# pragma comment(lib, "secur32.lib")
|
|
||||||
# pragma comment(lib, "winmm.lib")
|
|
||||||
# pragma comment(lib, "dmoguids.lib")
|
|
||||||
# pragma comment(lib, "wmcodecdspuuid.lib")
|
|
||||||
# pragma comment(lib, "msdmo.lib")
|
|
||||||
# pragma comment(lib, "Strmiids.lib")
|
|
||||||
# pragma comment(lib, "User32.lib")
|
|
||||||
|
|
||||||
void EnumCapture()
|
|
||||||
{
|
|
||||||
std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(
|
|
||||||
webrtc::VideoCaptureFactory::CreateDeviceInfo());
|
|
||||||
|
|
||||||
int num_devices = info->NumberOfDevices();
|
|
||||||
if (!info) {
|
|
||||||
RTC_LOG(LERROR) << "CreateDeviceInfo failed";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < num_devices; ++i) {
|
|
||||||
char name[128];
|
|
||||||
char id[128];
|
|
||||||
|
|
||||||
info->GetDeviceName(i,name,128,id,128,nullptr,0);
|
|
||||||
int cap_len = info->NumberOfCapabilities(id);
|
|
||||||
for(int j = 0;j < cap_len;j++){
|
|
||||||
webrtc::VideoCaptureCapability p;
|
|
||||||
info->GetCapability(id,j,p);
|
|
||||||
qDebug()<<QString::asprintf("GetCapability: %s %d %d ",id,p.width,p.height);
|
|
||||||
}
|
|
||||||
printf("%s\r\n",name);
|
|
||||||
//使用索引i创建capture对象
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
const size_t kWidth = 1280;
|
|
||||||
const size_t kHeight = 720;
|
|
||||||
const size_t kFps = 30;
|
|
||||||
|
|
||||||
std::unique_ptr<VcmCapturerTest> capturer;
|
|
||||||
std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(
|
|
||||||
webrtc::VideoCaptureFactory::CreateDeviceInfo());
|
|
||||||
if (!info) {
|
|
||||||
RTC_LOG(LERROR) << "CreateDeviceInfo failed";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int num_devices = info->NumberOfDevices();
|
|
||||||
for (int i = 0; i < num_devices; ++i) {
|
|
||||||
capturer.reset(VcmCapturerTest::Create(kWidth, kHeight, kFps, i));
|
|
||||||
if (capturer) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setbuf(stdout, NULL);
|
|
||||||
|
|
||||||
QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
|
|
||||||
QApplication a(argc, argv);
|
|
||||||
MainWindow w;
|
|
||||||
QObject::connect((VcmCapturerTest*)capturer.get(),SIGNAL( UpdateFrame(uint8_t *)),&w,
|
|
||||||
SLOT( OnUpdateFrame(uint8_t *)),Qt::ConnectionType::QueuedConnection);
|
|
||||||
|
|
||||||
w.show();
|
|
||||||
return a.exec();
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
#include "mainwindow.h"
|
|
||||||
#include "ui_mainwindow.h"
|
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent)
|
|
||||||
: QMainWindow(parent)
|
|
||||||
, ui(new Ui::MainWindow)
|
|
||||||
{
|
|
||||||
ui->setupUi(this);
|
|
||||||
ui->openGLWidget->SetImgSize(640,480);
|
|
||||||
ui->openGLWidget->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
|
||||||
{
|
|
||||||
delete ui;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::OnUpdateFrame(uint8_t *p)
|
|
||||||
{
|
|
||||||
qDebug()<<"1234";
|
|
||||||
ui->openGLWidget->OnCameraData(p,640*480);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
#ifndef MAINWINDOW_H
|
|
||||||
#define MAINWINDOW_H
|
|
||||||
|
|
||||||
#include <QMainWindow>
|
|
||||||
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
namespace Ui { class MainWindow; }
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
MainWindow(QWidget *parent = nullptr);
|
|
||||||
~MainWindow();
|
|
||||||
public slots:
|
|
||||||
void OnUpdateFrame(uint8_t *p);
|
|
||||||
private:
|
|
||||||
Ui::MainWindow *ui;
|
|
||||||
};
|
|
||||||
#endif // MAINWINDOW_H
|
|
|
@ -1,70 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>MainWindow</class>
|
|
||||||
<widget class="QMainWindow" name="MainWindow">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>1056</width>
|
|
||||||
<height>616</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>MainWindow</string>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="centralwidget">
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="1,12">
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,1,0,5">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>摄像头:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="comboBox"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>麦克风:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="comboBox_2"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="CPlayWidget" name="openGLWidget"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>CPlayWidget</class>
|
|
||||||
<extends>QOpenGLWidget</extends>
|
|
||||||
<header>cplaywidget.h</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
|
@ -1,113 +0,0 @@
|
||||||
#include "video_capture.h"
|
|
||||||
|
|
||||||
|
|
||||||
VcmCapturerTest::VcmCapturerTest() : vcm_(nullptr) {
|
|
||||||
rtc::LogMessage::SetLogToStderr(true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
VcmCapturerTest::~VcmCapturerTest() {
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VcmCapturerTest::Init(size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t target_fps,
|
|
||||||
size_t capture_device_index) {
|
|
||||||
std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> device_info(webrtc::VideoCaptureFactory::CreateDeviceInfo());
|
|
||||||
|
|
||||||
char device_name[256];
|
|
||||||
char unique_name[256];
|
|
||||||
|
|
||||||
if (device_info->GetDeviceName(static_cast<uint32_t>(capture_device_index),
|
|
||||||
device_name, sizeof(device_name), unique_name,
|
|
||||||
sizeof(unique_name)) != 0) {
|
|
||||||
Destroy();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
vcm_ = webrtc::VideoCaptureFactory::Create(unique_name);
|
|
||||||
if (!vcm_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
vcm_->RegisterCaptureDataCallback(this);
|
|
||||||
|
|
||||||
device_info->GetCapability(vcm_->CurrentDeviceName(), 0, capability_);
|
|
||||||
capability_.width = static_cast<int32_t>(width);
|
|
||||||
capability_.height = static_cast<int32_t>(height);
|
|
||||||
capability_.maxFPS = static_cast<int32_t>(target_fps);
|
|
||||||
capability_.videoType = webrtc::VideoType::kI420;
|
|
||||||
|
|
||||||
if (vcm_->StartCapture(capability_) != 0) {
|
|
||||||
Destroy();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RTC_CHECK(vcm_->CaptureStarted());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
VcmCapturerTest* VcmCapturerTest::Create(size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t target_fps,
|
|
||||||
size_t capture_device_index) {
|
|
||||||
std::unique_ptr<VcmCapturerTest> vcm_capturer(new VcmCapturerTest());
|
|
||||||
if (!vcm_capturer->Init(width, height, target_fps, capture_device_index)) {
|
|
||||||
RTC_LOG(LS_WARNING) << "Failed to create VcmCapturer(w = " << width
|
|
||||||
<< ", h = " << height << ", fps = " << target_fps
|
|
||||||
<< ")";
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return vcm_capturer.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VcmCapturerTest::Destroy() {
|
|
||||||
if (!vcm_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
vcm_->StopCapture();
|
|
||||||
vcm_->DeRegisterCaptureDataCallback();
|
|
||||||
// Release reference to VCM.
|
|
||||||
vcm_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VcmCapturerTest::OnFrame(const webrtc::VideoFrame& frame) {
|
|
||||||
static auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
||||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
|
||||||
static size_t cnt = 0;
|
|
||||||
|
|
||||||
RTC_LOG(LS_INFO) << "OnFrame "<<frame.width()<<" "<<frame.height()<<" "
|
|
||||||
<<frame.size()<<" "<<frame.timestamp()<<frame.video_frame_buffer().get()->type()<<" typed";
|
|
||||||
int nYUVBufsize = 0;
|
|
||||||
int nVOffset = 0;
|
|
||||||
int m_height = frame.height();
|
|
||||||
int m_width = frame.width();
|
|
||||||
|
|
||||||
uint8_t* m_uBuffer = new uint8_t[m_height * m_width + m_height * m_width/2];
|
|
||||||
for (int i = 0; i < m_height; i++) {
|
|
||||||
memcpy(m_uBuffer + nYUVBufsize,frame.video_frame_buffer().get()->GetI420()->DataY() +
|
|
||||||
i * frame.video_frame_buffer().get()->GetI420()->StrideY(), m_width);
|
|
||||||
|
|
||||||
nYUVBufsize += m_width;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < m_height / 2; i++) {
|
|
||||||
memcpy(m_uBuffer + nYUVBufsize, frame.video_frame_buffer().get()->GetI420()->DataU() +
|
|
||||||
i * frame.video_frame_buffer().get()->GetI420()->StrideU(), m_width / 2);
|
|
||||||
|
|
||||||
nYUVBufsize += m_width / 2;
|
|
||||||
memcpy(m_uBuffer + m_width * m_height * 5 / 4 + nVOffset, frame.video_frame_buffer().get()->GetI420()->DataV() +
|
|
||||||
i * frame.video_frame_buffer().get()->GetI420()->StrideV(), m_width / 2);
|
|
||||||
nVOffset += m_width / 2;
|
|
||||||
}
|
|
||||||
emit(this->UpdateFrame(m_uBuffer));
|
|
||||||
VideoCapturerTest::OnFrame(frame);
|
|
||||||
|
|
||||||
cnt++;
|
|
||||||
auto timestamp_curr = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
||||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
|
||||||
if(timestamp_curr - timestamp > 1000) {
|
|
||||||
RTC_LOG(LS_INFO) << "FPS: " << cnt;
|
|
||||||
cnt = 0;
|
|
||||||
timestamp = timestamp_curr;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
#ifndef VIDEO_CAPTURE_H
|
|
||||||
#define VIDEO_CAPTURE_H
|
|
||||||
|
|
||||||
// vcm_capturer_test.h
|
|
||||||
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <QObject>
|
|
||||||
#include "modules/video_capture/video_capture.h"
|
|
||||||
#include "video_capturer_test.h"
|
|
||||||
|
|
||||||
class VcmCapturerTest : public QObject,
|
|
||||||
public VideoCapturerTest,
|
|
||||||
public rtc::VideoSinkInterface<webrtc::VideoFrame>
|
|
||||||
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
VcmCapturerTest();
|
|
||||||
|
|
||||||
static VcmCapturerTest* Create(size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t target_fps,
|
|
||||||
size_t capture_device_index);
|
|
||||||
|
|
||||||
virtual ~VcmCapturerTest();
|
|
||||||
|
|
||||||
void OnFrame(const webrtc::VideoFrame& frame) override;
|
|
||||||
signals:
|
|
||||||
void UpdateFrame(uint8_t *p);
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
bool Init(size_t width,
|
|
||||||
size_t height,
|
|
||||||
size_t target_fps,
|
|
||||||
size_t capture_device_index);
|
|
||||||
|
|
||||||
void Destroy();
|
|
||||||
|
|
||||||
rtc::scoped_refptr<webrtc::VideoCaptureModule> vcm_;
|
|
||||||
webrtc::VideoCaptureCapability capability_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // VIDEO_CAPTURE_H
|
|
|
@ -1,75 +0,0 @@
|
||||||
#include "video_capturer_test.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include "api/video/i420_buffer.h"
|
|
||||||
#include "api/video/video_rotation.h"
|
|
||||||
#include "rtc_base/logging.h"
|
|
||||||
|
|
||||||
VideoCapturerTest::~VideoCapturerTest() = default;
|
|
||||||
|
|
||||||
void VideoCapturerTest::OnFrame(const webrtc::VideoFrame& original_frame) {
|
|
||||||
int cropped_width = 0;
|
|
||||||
int cropped_height = 0;
|
|
||||||
int out_width = 0;
|
|
||||||
int out_height = 0;
|
|
||||||
|
|
||||||
webrtc::VideoFrame frame = MaybePreprocess(original_frame);
|
|
||||||
|
|
||||||
if (!video_adapter_.AdaptFrameResolution(
|
|
||||||
frame.width(), frame.height(), frame.timestamp_us() * 1000,
|
|
||||||
&cropped_width, &cropped_height, &out_width, &out_height)) {
|
|
||||||
// Drop frame in order to respect frame rate constraint.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_height != frame.height() || out_width != frame.width()) {
|
|
||||||
// Video adapter has requested a down-scale. Allocate a new buffer and
|
|
||||||
// return scaled version.
|
|
||||||
// For simplicity, only scale here without cropping.
|
|
||||||
rtc::scoped_refptr<webrtc::I420Buffer> scaled_buffer =
|
|
||||||
webrtc::I420Buffer::Create(out_width, out_height);
|
|
||||||
scaled_buffer->ScaleFrom(*frame.video_frame_buffer()->ToI420());
|
|
||||||
webrtc::VideoFrame::Builder new_frame_builder =
|
|
||||||
webrtc::VideoFrame::Builder()
|
|
||||||
.set_video_frame_buffer(scaled_buffer)
|
|
||||||
.set_rotation(webrtc::kVideoRotation_0)
|
|
||||||
.set_timestamp_us(frame.timestamp_us())
|
|
||||||
.set_id(frame.id());
|
|
||||||
|
|
||||||
|
|
||||||
broadcaster_.OnFrame(new_frame_builder.build());
|
|
||||||
} else {
|
|
||||||
// No adaptations needed, just return the frame as is.
|
|
||||||
broadcaster_.OnFrame(frame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rtc::VideoSinkWants VideoCapturerTest::GetSinkWants() {
|
|
||||||
return broadcaster_.wants();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoCapturerTest::AddOrUpdateSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
|
|
||||||
const rtc::VideoSinkWants& wants) {
|
|
||||||
broadcaster_.AddOrUpdateSink(sink, wants);
|
|
||||||
UpdateVideoAdapter();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoCapturerTest::RemoveSink(
|
|
||||||
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
|
|
||||||
broadcaster_.RemoveSink(sink);
|
|
||||||
UpdateVideoAdapter();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoCapturerTest::UpdateVideoAdapter() {
|
|
||||||
video_adapter_.OnOutputFormatRequest(std::pair<int, int>(1,1),this->broadcaster_.wants().max_pixel_count,broadcaster_.wants().max_framerate_fps);
|
|
||||||
}
|
|
||||||
|
|
||||||
webrtc::VideoFrame VideoCapturerTest::MaybePreprocess(
|
|
||||||
const webrtc::VideoFrame& frame) {
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
if (preprocessor_ != nullptr) {
|
|
||||||
return preprocessor_->Preprocess(frame);
|
|
||||||
} else {
|
|
||||||
return frame;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
#ifndef VIDEO_CAPTURER_TEST_H
|
|
||||||
#define VIDEO_CAPTURER_TEST_H
|
|
||||||
|
|
||||||
#include "modules/video_capture/video_capture_factory.h"
|
|
||||||
#include "rtc_base/logging.h"
|
|
||||||
#include "modules/video_capture/video_capture_impl.h"
|
|
||||||
#include "api/video/i420_buffer.h"
|
|
||||||
#include "api/video/video_rotation.h"
|
|
||||||
#include "api/video/video_source_interface.h"
|
|
||||||
#include "rtc_base/logging.h"
|
|
||||||
#include "media/base/video_broadcaster.h"
|
|
||||||
#include "media/base/video_adapter.h"
|
|
||||||
#include <mutex>
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
class VideoCapturerTest : public QObject,
|
|
||||||
public rtc::VideoSourceInterface<webrtc::VideoFrame>{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
class FramePreprocessor {
|
|
||||||
public:
|
|
||||||
virtual ~FramePreprocessor() = default;
|
|
||||||
virtual webrtc::VideoFrame Preprocess(const webrtc::VideoFrame& frame) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
~VideoCapturerTest() override;
|
|
||||||
|
|
||||||
void AddOrUpdateSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
|
|
||||||
const rtc::VideoSinkWants& wants) override;
|
|
||||||
|
|
||||||
void RemoveSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) override;
|
|
||||||
|
|
||||||
void SetFramePreprocessor(std::unique_ptr<FramePreprocessor> preprocessor) {
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
preprocessor_ = std::move(preprocessor);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void OnFrame(const webrtc::VideoFrame& frame);
|
|
||||||
rtc::VideoSinkWants GetSinkWants();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void UpdateVideoAdapter();
|
|
||||||
webrtc::VideoFrame MaybePreprocess(const webrtc::VideoFrame& frame);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<FramePreprocessor> preprocessor_;
|
|
||||||
std::mutex mutex_;
|
|
||||||
rtc::VideoBroadcaster broadcaster_;
|
|
||||||
cricket::VideoAdapter video_adapter_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // VIDEO_CAPTURER_TEST_H
|
|
|
@ -1,159 +0,0 @@
|
||||||
// Copyright 2017 The Abseil Authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// File: algorithm.h
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This header file contains Google extensions to the standard <algorithm> C++
|
|
||||||
// header.
|
|
||||||
|
|
||||||
#ifndef ABSL_ALGORITHM_ALGORITHM_H_
|
|
||||||
#define ABSL_ALGORITHM_ALGORITHM_H_
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <iterator>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "absl/base/config.h"
|
|
||||||
|
|
||||||
namespace absl {
|
|
||||||
ABSL_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
namespace algorithm_internal {
|
|
||||||
|
|
||||||
// Performs comparisons with operator==, similar to C++14's `std::equal_to<>`.
|
|
||||||
struct EqualTo {
|
|
||||||
template <typename T, typename U>
|
|
||||||
bool operator()(const T& a, const U& b) const {
|
|
||||||
return a == b;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename InputIter1, typename InputIter2, typename Pred>
|
|
||||||
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
|
||||||
InputIter2 last2, Pred pred, std::input_iterator_tag,
|
|
||||||
std::input_iterator_tag) {
|
|
||||||
while (true) {
|
|
||||||
if (first1 == last1) return first2 == last2;
|
|
||||||
if (first2 == last2) return false;
|
|
||||||
if (!pred(*first1, *first2)) return false;
|
|
||||||
++first1;
|
|
||||||
++first2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename InputIter1, typename InputIter2, typename Pred>
|
|
||||||
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
|
||||||
InputIter2 last2, Pred&& pred, std::random_access_iterator_tag,
|
|
||||||
std::random_access_iterator_tag) {
|
|
||||||
return (last1 - first1 == last2 - first2) &&
|
|
||||||
std::equal(first1, last1, first2, std::forward<Pred>(pred));
|
|
||||||
}
|
|
||||||
|
|
||||||
// When we are using our own internal predicate that just applies operator==, we
|
|
||||||
// forward to the non-predicate form of std::equal. This enables an optimization
|
|
||||||
// in libstdc++ that can result in std::memcmp being used for integer types.
|
|
||||||
template <typename InputIter1, typename InputIter2>
|
|
||||||
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
|
||||||
InputIter2 last2, algorithm_internal::EqualTo /* unused */,
|
|
||||||
std::random_access_iterator_tag,
|
|
||||||
std::random_access_iterator_tag) {
|
|
||||||
return (last1 - first1 == last2 - first2) &&
|
|
||||||
std::equal(first1, last1, first2);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename It>
|
|
||||||
It RotateImpl(It first, It middle, It last, std::true_type) {
|
|
||||||
return std::rotate(first, middle, last);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename It>
|
|
||||||
It RotateImpl(It first, It middle, It last, std::false_type) {
|
|
||||||
std::rotate(first, middle, last);
|
|
||||||
return std::next(first, std::distance(middle, last));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace algorithm_internal
|
|
||||||
|
|
||||||
// equal()
|
|
||||||
//
|
|
||||||
// Compares the equality of two ranges specified by pairs of iterators, using
|
|
||||||
// the given predicate, returning true iff for each corresponding iterator i1
|
|
||||||
// and i2 in the first and second range respectively, pred(*i1, *i2) == true
|
|
||||||
//
|
|
||||||
// This comparison takes at most min(`last1` - `first1`, `last2` - `first2`)
|
|
||||||
// invocations of the predicate. Additionally, if InputIter1 and InputIter2 are
|
|
||||||
// both random-access iterators, and `last1` - `first1` != `last2` - `first2`,
|
|
||||||
// then the predicate is never invoked and the function returns false.
|
|
||||||
//
|
|
||||||
// This is a C++11-compatible implementation of C++14 `std::equal`. See
|
|
||||||
// https://en.cppreference.com/w/cpp/algorithm/equal for more information.
|
|
||||||
template <typename InputIter1, typename InputIter2, typename Pred>
|
|
||||||
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
|
||||||
InputIter2 last2, Pred&& pred) {
|
|
||||||
return algorithm_internal::EqualImpl(
|
|
||||||
first1, last1, first2, last2, std::forward<Pred>(pred),
|
|
||||||
typename std::iterator_traits<InputIter1>::iterator_category{},
|
|
||||||
typename std::iterator_traits<InputIter2>::iterator_category{});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overload of equal() that performs comparison of two ranges specified by pairs
|
|
||||||
// of iterators using operator==.
|
|
||||||
template <typename InputIter1, typename InputIter2>
|
|
||||||
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
|
||||||
InputIter2 last2) {
|
|
||||||
return absl::equal(first1, last1, first2, last2,
|
|
||||||
algorithm_internal::EqualTo{});
|
|
||||||
}
|
|
||||||
|
|
||||||
// linear_search()
|
|
||||||
//
|
|
||||||
// Performs a linear search for `value` using the iterator `first` up to
|
|
||||||
// but not including `last`, returning true if [`first`, `last`) contains an
|
|
||||||
// element equal to `value`.
|
|
||||||
//
|
|
||||||
// A linear search is of O(n) complexity which is guaranteed to make at most
|
|
||||||
// n = (`last` - `first`) comparisons. A linear search over short containers
|
|
||||||
// may be faster than a binary search, even when the container is sorted.
|
|
||||||
template <typename InputIterator, typename EqualityComparable>
|
|
||||||
bool linear_search(InputIterator first, InputIterator last,
|
|
||||||
const EqualityComparable& value) {
|
|
||||||
return std::find(first, last, value) != last;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rotate()
|
|
||||||
//
|
|
||||||
// Performs a left rotation on a range of elements (`first`, `last`) such that
|
|
||||||
// `middle` is now the first element. `rotate()` returns an iterator pointing to
|
|
||||||
// the first element before rotation. This function is exactly the same as
|
|
||||||
// `std::rotate`, but fixes a bug in gcc
|
|
||||||
// <= 4.9 where `std::rotate` returns `void` instead of an iterator.
|
|
||||||
//
|
|
||||||
// The complexity of this algorithm is the same as that of `std::rotate`, but if
|
|
||||||
// `ForwardIterator` is not a random-access iterator, then `absl::rotate`
|
|
||||||
// performs an additional pass over the range to construct the return value.
|
|
||||||
template <typename ForwardIterator>
|
|
||||||
ForwardIterator rotate(ForwardIterator first, ForwardIterator middle,
|
|
||||||
ForwardIterator last) {
|
|
||||||
return algorithm_internal::RotateImpl(
|
|
||||||
first, middle, last,
|
|
||||||
std::is_same<decltype(std::rotate(first, middle, last)),
|
|
||||||
ForwardIterator>());
|
|
||||||
}
|
|
||||||
|
|
||||||
ABSL_NAMESPACE_END
|
|
||||||
} // namespace absl
|
|
||||||
|
|
||||||
#endif // ABSL_ALGORITHM_ALGORITHM_H_
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,702 +0,0 @@
|
||||||
// Copyright 2017 The Abseil Authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
// This header file defines macros for declaring attributes for functions,
|
|
||||||
// types, and variables.
|
|
||||||
//
|
|
||||||
// These macros are used within Abseil and allow the compiler to optimize, where
|
|
||||||
// applicable, certain function calls.
|
|
||||||
//
|
|
||||||
// Most macros here are exposing GCC or Clang features, and are stubbed out for
|
|
||||||
// other compilers.
|
|
||||||
//
|
|
||||||
// GCC attributes documentation:
|
|
||||||
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
|
|
||||||
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html
|
|
||||||
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html
|
|
||||||
//
|
|
||||||
// Most attributes in this file are already supported by GCC 4.7. However, some
|
|
||||||
// of them are not supported in older version of Clang. Thus, we check
|
|
||||||
// `__has_attribute()` first. If the check fails, we check if we are on GCC and
|
|
||||||
// assume the attribute exists on GCC (which is verified on GCC 4.7).
|
|
||||||
|
|
||||||
#ifndef ABSL_BASE_ATTRIBUTES_H_
|
|
||||||
#define ABSL_BASE_ATTRIBUTES_H_
|
|
||||||
|
|
||||||
#include "absl/base/config.h"
|
|
||||||
|
|
||||||
// ABSL_HAVE_ATTRIBUTE
|
|
||||||
//
|
|
||||||
// A function-like feature checking macro that is a wrapper around
|
|
||||||
// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
|
|
||||||
// nonzero constant integer if the attribute is supported or 0 if not.
|
|
||||||
//
|
|
||||||
// It evaluates to zero if `__has_attribute` is not defined by the compiler.
|
|
||||||
//
|
|
||||||
// GCC: https://gcc.gnu.org/gcc-5/changes.html
|
|
||||||
// Clang: https://clang.llvm.org/docs/LanguageExtensions.html
|
|
||||||
#ifdef __has_attribute
|
|
||||||
#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
|
|
||||||
#else
|
|
||||||
#define ABSL_HAVE_ATTRIBUTE(x) 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_HAVE_CPP_ATTRIBUTE
|
|
||||||
//
|
|
||||||
// A function-like feature checking macro that accepts C++11 style attributes.
|
|
||||||
// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
|
|
||||||
// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
|
|
||||||
// find `__has_cpp_attribute`, will evaluate to 0.
|
|
||||||
#if defined(__cplusplus) && defined(__has_cpp_attribute)
|
|
||||||
// NOTE: requiring __cplusplus above should not be necessary, but
|
|
||||||
// works around https://bugs.llvm.org/show_bug.cgi?id=23435.
|
|
||||||
#define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
|
|
||||||
#else
|
|
||||||
#define ABSL_HAVE_CPP_ATTRIBUTE(x) 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// Function Attributes
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
|
||||||
// Clang: https://clang.llvm.org/docs/AttributeReference.html
|
|
||||||
|
|
||||||
// ABSL_PRINTF_ATTRIBUTE
|
|
||||||
// ABSL_SCANF_ATTRIBUTE
|
|
||||||
//
|
|
||||||
// Tells the compiler to perform `printf` format string checking if the
|
|
||||||
// compiler supports it; see the 'format' attribute in
|
|
||||||
// <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
|
|
||||||
//
|
|
||||||
// Note: As the GCC manual states, "[s]ince non-static C++ methods
|
|
||||||
// have an implicit 'this' argument, the arguments of such methods
|
|
||||||
// should be counted from two, not one."
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
|
|
||||||
__attribute__((__format__(__printf__, string_index, first_to_check)))
|
|
||||||
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \
|
|
||||||
__attribute__((__format__(__scanf__, string_index, first_to_check)))
|
|
||||||
#else
|
|
||||||
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check)
|
|
||||||
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_ALWAYS_INLINE
|
|
||||||
// ABSL_ATTRIBUTE_NOINLINE
|
|
||||||
//
|
|
||||||
// Forces functions to either inline or not inline. Introduced in gcc 3.1.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(always_inline) || \
|
|
||||||
(defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
|
|
||||||
#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_ALWAYS_INLINE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline))
|
|
||||||
#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_NOINLINE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_NO_TAIL_CALL
|
|
||||||
//
|
|
||||||
// Prevents the compiler from optimizing away stack frames for functions which
|
|
||||||
// end in a call to another function.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
|
|
||||||
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
|
|
||||||
#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
|
|
||||||
#elif defined(__GNUC__) && !defined(__clang__) && !defined(__e2k__)
|
|
||||||
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
|
|
||||||
#define ABSL_ATTRIBUTE_NO_TAIL_CALL \
|
|
||||||
__attribute__((optimize("no-optimize-sibling-calls")))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_NO_TAIL_CALL
|
|
||||||
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_WEAK
|
|
||||||
//
|
|
||||||
// Tags a function as weak for the purposes of compilation and linking.
|
|
||||||
// Weak attributes currently do not work properly in LLVM's Windows backend,
|
|
||||||
// so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
|
|
||||||
// for further information.
|
|
||||||
// The MinGW compiler doesn't complain about the weak attribute until the link
|
|
||||||
// step, presumably because Windows doesn't use ELF binaries.
|
|
||||||
#if (ABSL_HAVE_ATTRIBUTE(weak) || \
|
|
||||||
(defined(__GNUC__) && !defined(__clang__))) && \
|
|
||||||
!(defined(__llvm__) && defined(_WIN32)) && !defined(__MINGW32__)
|
|
||||||
#undef ABSL_ATTRIBUTE_WEAK
|
|
||||||
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
|
|
||||||
#define ABSL_HAVE_ATTRIBUTE_WEAK 1
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_WEAK
|
|
||||||
#define ABSL_HAVE_ATTRIBUTE_WEAK 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_NONNULL
|
|
||||||
//
|
|
||||||
// Tells the compiler either (a) that a particular function parameter
|
|
||||||
// should be a non-null pointer, or (b) that all pointer arguments should
|
|
||||||
// be non-null.
|
|
||||||
//
|
|
||||||
// Note: As the GCC manual states, "[s]ince non-static C++ methods
|
|
||||||
// have an implicit 'this' argument, the arguments of such methods
|
|
||||||
// should be counted from two, not one."
|
|
||||||
//
|
|
||||||
// Args are indexed starting at 1.
|
|
||||||
//
|
|
||||||
// For non-static class member functions, the implicit `this` argument
|
|
||||||
// is arg 1, and the first explicit argument is arg 2. For static class member
|
|
||||||
// functions, there is no implicit `this`, and the first explicit argument is
|
|
||||||
// arg 1.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// /* arg_a cannot be null, but arg_b can */
|
|
||||||
// void Function(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(1);
|
|
||||||
//
|
|
||||||
// class C {
|
|
||||||
// /* arg_a cannot be null, but arg_b can */
|
|
||||||
// void Method(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(2);
|
|
||||||
//
|
|
||||||
// /* arg_a cannot be null, but arg_b can */
|
|
||||||
// static void StaticMethod(void* arg_a, void* arg_b)
|
|
||||||
// ABSL_ATTRIBUTE_NONNULL(1);
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// If no arguments are provided, then all pointer arguments should be non-null.
|
|
||||||
//
|
|
||||||
// /* No pointer arguments may be null. */
|
|
||||||
// void Function(void* arg_a, void* arg_b, int arg_c) ABSL_ATTRIBUTE_NONNULL();
|
|
||||||
//
|
|
||||||
// NOTE: The GCC nonnull attribute actually accepts a list of arguments, but
|
|
||||||
// ABSL_ATTRIBUTE_NONNULL does not.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_NONNULL(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_NORETURN
|
|
||||||
//
|
|
||||||
// Tells the compiler that a given function never returns.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn))
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn)
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_NORETURN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
|
|
||||||
//
|
|
||||||
// Tells the AddressSanitizer (or other memory testing tools) to ignore a given
|
|
||||||
// function. Useful for cases when a function reads random locations on stack,
|
|
||||||
// calls _exit from a cloned subprocess, deliberately accesses buffer
|
|
||||||
// out of bounds or does other scary things with memory.
|
|
||||||
// NOTE: GCC supports AddressSanitizer(asan) since 4.8.
|
|
||||||
// https://gcc.gnu.org/gcc-4.8/changes.html
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_address)
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
|
|
||||||
//
|
|
||||||
// Tells the MemorySanitizer to relax the handling of a given function. All "Use
|
|
||||||
// of uninitialized value" warnings from such functions will be suppressed, and
|
|
||||||
// all values loaded from memory will be considered fully initialized. This
|
|
||||||
// attribute is similar to the ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS attribute
|
|
||||||
// above, but deals with initialized-ness rather than addressability issues.
|
|
||||||
// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory)
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
|
|
||||||
//
|
|
||||||
// Tells the ThreadSanitizer to not instrument a given function.
|
|
||||||
// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
|
|
||||||
// https://gcc.gnu.org/gcc-4.8/changes.html
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread)
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
|
||||||
//
|
|
||||||
// Tells the UndefinedSanitizer to ignore a given function. Useful for cases
|
|
||||||
// where certain behavior (eg. division by zero) is being used intentionally.
|
|
||||||
// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
|
|
||||||
// https://gcc.gnu.org/gcc-4.9/changes.html
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_undefined)
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
|
|
||||||
__attribute__((no_sanitize_undefined))
|
|
||||||
#elif ABSL_HAVE_ATTRIBUTE(no_sanitize)
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
|
|
||||||
__attribute__((no_sanitize("undefined")))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_NO_SANITIZE_CFI
|
|
||||||
//
|
|
||||||
// Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
|
|
||||||
// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
|
|
||||||
//
|
|
||||||
// Tells the SafeStack to not instrument a given function.
|
|
||||||
// See https://clang.llvm.org/docs/SafeStack.html for details.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
|
|
||||||
__attribute__((no_sanitize("safe-stack")))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_RETURNS_NONNULL
|
|
||||||
//
|
|
||||||
// Tells the compiler that a particular function never returns a null pointer.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(returns_nonnull) || \
|
|
||||||
(defined(__GNUC__) && \
|
|
||||||
(__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \
|
|
||||||
!defined(__clang__))
|
|
||||||
#define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_RETURNS_NONNULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_HAVE_ATTRIBUTE_SECTION
|
|
||||||
//
|
|
||||||
// Indicates whether labeled sections are supported. Weak symbol support is
|
|
||||||
// a prerequisite. Labeled sections are not supported on Darwin/iOS.
|
|
||||||
#ifdef ABSL_HAVE_ATTRIBUTE_SECTION
|
|
||||||
#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set
|
|
||||||
#elif (ABSL_HAVE_ATTRIBUTE(section) || \
|
|
||||||
(defined(__GNUC__) && !defined(__clang__))) && \
|
|
||||||
!defined(__APPLE__) && ABSL_HAVE_ATTRIBUTE_WEAK
|
|
||||||
#define ABSL_HAVE_ATTRIBUTE_SECTION 1
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_SECTION
|
|
||||||
//
|
|
||||||
// Tells the compiler/linker to put a given function into a section and define
|
|
||||||
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
|
|
||||||
// This functionality is supported by GNU linker. Any function annotated with
|
|
||||||
// `ABSL_ATTRIBUTE_SECTION` must not be inlined, or it will be placed into
|
|
||||||
// whatever section its caller is placed into.
|
|
||||||
//
|
|
||||||
#ifndef ABSL_ATTRIBUTE_SECTION
|
|
||||||
#define ABSL_ATTRIBUTE_SECTION(name) \
|
|
||||||
__attribute__((section(#name))) __attribute__((noinline))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_SECTION_VARIABLE
|
|
||||||
//
|
|
||||||
// Tells the compiler/linker to put a given variable into a section and define
|
|
||||||
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
|
|
||||||
// This functionality is supported by GNU linker.
|
|
||||||
#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE
|
|
||||||
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
|
|
||||||
//
|
|
||||||
// A weak section declaration to be used as a global declaration
|
|
||||||
// for ABSL_ATTRIBUTE_SECTION_START|STOP(name) to compile and link
|
|
||||||
// even without functions with ABSL_ATTRIBUTE_SECTION(name).
|
|
||||||
// ABSL_DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's
|
|
||||||
// a no-op on ELF but not on Mach-O.
|
|
||||||
//
|
|
||||||
#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
|
|
||||||
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
|
|
||||||
extern char __start_##name[] ABSL_ATTRIBUTE_WEAK; \
|
|
||||||
extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK
|
|
||||||
#endif
|
|
||||||
#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS
|
|
||||||
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
|
|
||||||
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_SECTION_START
|
|
||||||
//
|
|
||||||
// Returns `void*` pointers to start/end of a section of code with
|
|
||||||
// functions having ABSL_ATTRIBUTE_SECTION(name).
|
|
||||||
// Returns 0 if no such functions exist.
|
|
||||||
// One must ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and
|
|
||||||
// link.
|
|
||||||
//
|
|
||||||
#define ABSL_ATTRIBUTE_SECTION_START(name) \
|
|
||||||
(reinterpret_cast<void *>(__start_##name))
|
|
||||||
#define ABSL_ATTRIBUTE_SECTION_STOP(name) \
|
|
||||||
(reinterpret_cast<void *>(__stop_##name))
|
|
||||||
|
|
||||||
#else // !ABSL_HAVE_ATTRIBUTE_SECTION
|
|
||||||
|
|
||||||
#define ABSL_HAVE_ATTRIBUTE_SECTION 0
|
|
||||||
|
|
||||||
// provide dummy definitions
|
|
||||||
#define ABSL_ATTRIBUTE_SECTION(name)
|
|
||||||
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
|
|
||||||
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
|
|
||||||
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
|
|
||||||
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name)
|
|
||||||
#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
|
|
||||||
#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
|
|
||||||
|
|
||||||
#endif // ABSL_ATTRIBUTE_SECTION
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
|
||||||
//
|
|
||||||
// Support for aligning the stack on 32-bit x86.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || \
|
|
||||||
(defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#if defined(__i386__)
|
|
||||||
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \
|
|
||||||
__attribute__((force_align_arg_pointer))
|
|
||||||
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
|
||||||
#elif defined(__x86_64__)
|
|
||||||
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
|
|
||||||
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
|
||||||
#else // !__i386__ && !__x86_64
|
|
||||||
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
|
||||||
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
|
||||||
#endif // __i386__
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
|
||||||
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_MUST_USE_RESULT
|
|
||||||
//
|
|
||||||
// Tells the compiler to warn about unused results.
|
|
||||||
//
|
|
||||||
// When annotating a function, it must appear as the first part of the
|
|
||||||
// declaration or definition. The compiler will warn if the return value from
|
|
||||||
// such a function is unused:
|
|
||||||
//
|
|
||||||
// ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket();
|
|
||||||
// AllocateSprocket(); // Triggers a warning.
|
|
||||||
//
|
|
||||||
// When annotating a class, it is equivalent to annotating every function which
|
|
||||||
// returns an instance.
|
|
||||||
//
|
|
||||||
// class ABSL_MUST_USE_RESULT Sprocket {};
|
|
||||||
// Sprocket(); // Triggers a warning.
|
|
||||||
//
|
|
||||||
// Sprocket MakeSprocket();
|
|
||||||
// MakeSprocket(); // Triggers a warning.
|
|
||||||
//
|
|
||||||
// Note that references and pointers are not instances:
|
|
||||||
//
|
|
||||||
// Sprocket* SprocketPointer();
|
|
||||||
// SprocketPointer(); // Does *not* trigger a warning.
|
|
||||||
//
|
|
||||||
// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result
|
|
||||||
// warning. For that, warn_unused_result is used only for clang but not for gcc.
|
|
||||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
|
|
||||||
//
|
|
||||||
// Note: past advice was to place the macro after the argument list.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(nodiscard)
|
|
||||||
#define ABSL_MUST_USE_RESULT [[nodiscard]]
|
|
||||||
#elif defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
|
|
||||||
#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
|
|
||||||
#else
|
|
||||||
#define ABSL_MUST_USE_RESULT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD
|
|
||||||
//
|
|
||||||
// Tells GCC that a function is hot or cold. GCC can use this information to
|
|
||||||
// improve static analysis, i.e. a conditional branch to a cold function
|
|
||||||
// is likely to be not-taken.
|
|
||||||
// This annotation is used for function declarations.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// int foo() ABSL_ATTRIBUTE_HOT;
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#define ABSL_ATTRIBUTE_HOT __attribute__((hot))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_HOT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#define ABSL_ATTRIBUTE_COLD __attribute__((cold))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_COLD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS
|
|
||||||
//
|
|
||||||
// We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT
|
|
||||||
// macro used as an attribute to mark functions that must always or never be
|
|
||||||
// instrumented by XRay. Currently, this is only supported in Clang/LLVM.
|
|
||||||
//
|
|
||||||
// For reference on the LLVM XRay instrumentation, see
|
|
||||||
// http://llvm.org/docs/XRay.html.
|
|
||||||
//
|
|
||||||
// A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration
|
|
||||||
// will always get the XRay instrumentation sleds. These sleds may introduce
|
|
||||||
// some binary size and runtime overhead and must be used sparingly.
|
|
||||||
//
|
|
||||||
// These attributes only take effect when the following conditions are met:
|
|
||||||
//
|
|
||||||
// * The file/target is built in at least C++11 mode, with a Clang compiler
|
|
||||||
// that supports XRay attributes.
|
|
||||||
// * The file/target is built with the -fxray-instrument flag set for the
|
|
||||||
// Clang/LLVM compiler.
|
|
||||||
// * The function is defined in the translation unit (the compiler honors the
|
|
||||||
// attribute in either the definition or the declaration, and must match).
|
|
||||||
//
|
|
||||||
// There are cases when, even when building with XRay instrumentation, users
|
|
||||||
// might want to control specifically which functions are instrumented for a
|
|
||||||
// particular build using special-case lists provided to the compiler. These
|
|
||||||
// special case lists are provided to Clang via the
|
|
||||||
// -fxray-always-instrument=... and -fxray-never-instrument=... flags. The
|
|
||||||
// attributes in source take precedence over these special-case lists.
|
|
||||||
//
|
|
||||||
// To disable the XRay attributes at build-time, users may define
|
|
||||||
// ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific
|
|
||||||
// packages/targets, as this may lead to conflicting definitions of functions at
|
|
||||||
// link-time.
|
|
||||||
//
|
|
||||||
// XRay isn't currently supported on Android:
|
|
||||||
// https://github.com/android/ndk/issues/368
|
|
||||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
|
|
||||||
!defined(ABSL_NO_XRAY_ATTRIBUTES) && !defined(__ANDROID__)
|
|
||||||
#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
|
|
||||||
#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
|
|
||||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
|
|
||||||
#define ABSL_XRAY_LOG_ARGS(N) \
|
|
||||||
[[clang::xray_always_instrument, clang::xray_log_args(N)]]
|
|
||||||
#else
|
|
||||||
#define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]]
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define ABSL_XRAY_ALWAYS_INSTRUMENT
|
|
||||||
#define ABSL_XRAY_NEVER_INSTRUMENT
|
|
||||||
#define ABSL_XRAY_LOG_ARGS(N)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_REINITIALIZES
|
|
||||||
//
|
|
||||||
// Indicates that a member function reinitializes the entire object to a known
|
|
||||||
// state, independent of the previous state of the object.
|
|
||||||
//
|
|
||||||
// The clang-tidy check bugprone-use-after-move allows member functions marked
|
|
||||||
// with this attribute to be called on objects that have been moved from;
|
|
||||||
// without the attribute, this would result in a use-after-move warning.
|
|
||||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::reinitializes)
|
|
||||||
#define ABSL_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_REINITIALIZES
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// Variable Attributes
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_UNUSED
|
|
||||||
//
|
|
||||||
// Prevents the compiler from complaining about variables that appear unused.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#undef ABSL_ATTRIBUTE_UNUSED
|
|
||||||
#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_UNUSED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_INITIAL_EXEC
|
|
||||||
//
|
|
||||||
// Tells the compiler to use "initial-exec" mode for a thread-local variable.
|
|
||||||
// See http://people.redhat.com/drepper/tls.pdf for the gory details.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_INITIAL_EXEC
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_PACKED
|
|
||||||
//
|
|
||||||
// Instructs the compiler not to use natural alignment for a tagged data
|
|
||||||
// structure, but instead to reduce its alignment to 1. This attribute can
|
|
||||||
// either be applied to members of a structure or to a structure in its
|
|
||||||
// entirety. Applying this attribute (judiciously) to a structure in its
|
|
||||||
// entirety to optimize the memory footprint of very commonly-used structs is
|
|
||||||
// fine. Do not apply this attribute to a structure in its entirety if the
|
|
||||||
// purpose is to control the offsets of the members in the structure. Instead,
|
|
||||||
// apply this attribute only to structure members that need it.
|
|
||||||
//
|
|
||||||
// When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the
|
|
||||||
// natural alignment of structure members not annotated is preserved. Aligned
|
|
||||||
// member accesses are faster than non-aligned member accesses even if the
|
|
||||||
// targeted microprocessor supports non-aligned accesses.
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_PACKED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_FUNC_ALIGN
|
|
||||||
//
|
|
||||||
// Tells the compiler to align the function start at least to certain
|
|
||||||
// alignment boundary
|
|
||||||
#if ABSL_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
|
|
||||||
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_FALLTHROUGH_INTENDED
|
|
||||||
//
|
|
||||||
// Annotates implicit fall-through between switch labels, allowing a case to
|
|
||||||
// indicate intentional fallthrough and turn off warnings about any lack of a
|
|
||||||
// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
|
|
||||||
// a semicolon and can be used in most places where `break` can, provided that
|
|
||||||
// no statements exist between it and the next switch label.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// switch (x) {
|
|
||||||
// case 40:
|
|
||||||
// case 41:
|
|
||||||
// if (truth_is_out_there) {
|
|
||||||
// ++x;
|
|
||||||
// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations
|
|
||||||
// // in comments
|
|
||||||
// } else {
|
|
||||||
// return x;
|
|
||||||
// }
|
|
||||||
// case 42:
|
|
||||||
// ...
|
|
||||||
//
|
|
||||||
// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
|
|
||||||
// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
|
|
||||||
// when performing switch labels fall-through diagnostic
|
|
||||||
// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
|
|
||||||
// for details:
|
|
||||||
// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
|
|
||||||
//
|
|
||||||
// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
|
|
||||||
// has no effect on diagnostics. In any case this macro has no effect on runtime
|
|
||||||
// behavior and performance of code.
|
|
||||||
|
|
||||||
#ifdef ABSL_FALLTHROUGH_INTENDED
|
|
||||||
#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
|
|
||||||
#if defined(__clang__) && defined(__has_warning)
|
|
||||||
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
|
|
||||||
#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
|
|
||||||
#endif
|
|
||||||
#elif defined(__GNUC__) && __GNUC__ >= 7
|
|
||||||
#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ABSL_FALLTHROUGH_INTENDED
|
|
||||||
#define ABSL_FALLTHROUGH_INTENDED \
|
|
||||||
do { \
|
|
||||||
} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_DEPRECATED()
|
|
||||||
//
|
|
||||||
// Marks a deprecated class, struct, enum, function, method and variable
|
|
||||||
// declarations. The macro argument is used as a custom diagnostic message (e.g.
|
|
||||||
// suggestion of a better alternative).
|
|
||||||
//
|
|
||||||
// Examples:
|
|
||||||
//
|
|
||||||
// class ABSL_DEPRECATED("Use Bar instead") Foo {...};
|
|
||||||
//
|
|
||||||
// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
|
|
||||||
//
|
|
||||||
// template <typename T>
|
|
||||||
// ABSL_DEPRECATED("Use DoThat() instead")
|
|
||||||
// void DoThis();
|
|
||||||
//
|
|
||||||
// Every usage of a deprecated entity will trigger a warning when compiled with
|
|
||||||
// clang's `-Wdeprecated-declarations` option. This option is turned off by
|
|
||||||
// default, but the warnings will be reported by clang-tidy.
|
|
||||||
#if defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L
|
|
||||||
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ABSL_DEPRECATED
|
|
||||||
#define ABSL_DEPRECATED(message)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ABSL_CONST_INIT
|
|
||||||
//
|
|
||||||
// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
|
|
||||||
// not compile (on supported platforms) unless the variable has a constant
|
|
||||||
// initializer. This is useful for variables with static and thread storage
|
|
||||||
// duration, because it guarantees that they will not suffer from the so-called
|
|
||||||
// "static init order fiasco". Prefer to put this attribute on the most visible
|
|
||||||
// declaration of the variable, if there's more than one, because code that
|
|
||||||
// accesses the variable can then use the attribute for optimization.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// class MyClass {
|
|
||||||
// public:
|
|
||||||
// ABSL_CONST_INIT static MyType my_var;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// MyType MyClass::my_var = MakeMyType(...);
|
|
||||||
//
|
|
||||||
// Note that this attribute is redundant if the variable is declared constexpr.
|
|
||||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
|
|
||||||
#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
|
|
||||||
#else
|
|
||||||
#define ABSL_CONST_INIT
|
|
||||||
#endif // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
|
|
||||||
|
|
||||||
// ABSL_ATTRIBUTE_PURE_FUNCTION
|
|
||||||
//
|
|
||||||
// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure"
|
|
||||||
// functions. A function is pure if its return value is only a function of its
|
|
||||||
// arguments. The pure attribute prohibits a function from modifying the state
|
|
||||||
// of the program that is observable by means other than inspecting the
|
|
||||||
// function's return value. Declaring such functions with the pure attribute
|
|
||||||
// allows the compiler to avoid emitting some calls in repeated invocations of
|
|
||||||
// the function with the same argument values.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d);
|
|
||||||
#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::pure)
|
|
||||||
#define ABSL_ATTRIBUTE_PURE_FUNCTION [[gnu::pure]]
|
|
||||||
#elif ABSL_HAVE_ATTRIBUTE(pure)
|
|
||||||
#define ABSL_ATTRIBUTE_PURE_FUNCTION __attribute__((pure))
|
|
||||||
#else
|
|
||||||
#define ABSL_ATTRIBUTE_PURE_FUNCTION
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // ABSL_BASE_ATTRIBUTES_H_
|
|
|
@ -1,219 +0,0 @@
|
||||||
// Copyright 2017 The Abseil Authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// File: call_once.h
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This header file provides an Abseil version of `std::call_once` for invoking
|
|
||||||
// a given function at most once, across all threads. This Abseil version is
|
|
||||||
// faster than the C++11 version and incorporates the C++17 argument-passing
|
|
||||||
// fix, so that (for example) non-const references may be passed to the invoked
|
|
||||||
// function.
|
|
||||||
|
|
||||||
#ifndef ABSL_BASE_CALL_ONCE_H_
|
|
||||||
#define ABSL_BASE_CALL_ONCE_H_
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <atomic>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "absl/base/internal/invoke.h"
|
|
||||||
#include "absl/base/internal/low_level_scheduling.h"
|
|
||||||
#include "absl/base/internal/raw_logging.h"
|
|
||||||
#include "absl/base/internal/scheduling_mode.h"
|
|
||||||
#include "absl/base/internal/spinlock_wait.h"
|
|
||||||
#include "absl/base/macros.h"
|
|
||||||
#include "absl/base/optimization.h"
|
|
||||||
#include "absl/base/port.h"
|
|
||||||
|
|
||||||
namespace absl {
|
|
||||||
ABSL_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
class once_flag;
|
|
||||||
|
|
||||||
namespace base_internal {
|
|
||||||
std::atomic<uint32_t>* ControlWord(absl::once_flag* flag);
|
|
||||||
} // namespace base_internal
|
|
||||||
|
|
||||||
// call_once()
|
|
||||||
//
|
|
||||||
// For all invocations using a given `once_flag`, invokes a given `fn` exactly
|
|
||||||
// once across all threads. The first call to `call_once()` with a particular
|
|
||||||
// `once_flag` argument (that does not throw an exception) will run the
|
|
||||||
// specified function with the provided `args`; other calls with the same
|
|
||||||
// `once_flag` argument will not run the function, but will wait
|
|
||||||
// for the provided function to finish running (if it is still running).
|
|
||||||
//
|
|
||||||
// This mechanism provides a safe, simple, and fast mechanism for one-time
|
|
||||||
// initialization in a multi-threaded process.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// class MyInitClass {
|
|
||||||
// public:
|
|
||||||
// ...
|
|
||||||
// mutable absl::once_flag once_;
|
|
||||||
//
|
|
||||||
// MyInitClass* init() const {
|
|
||||||
// absl::call_once(once_, &MyInitClass::Init, this);
|
|
||||||
// return ptr_;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
template <typename Callable, typename... Args>
|
|
||||||
void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args);
|
|
||||||
|
|
||||||
// once_flag
|
|
||||||
//
|
|
||||||
// Objects of this type are used to distinguish calls to `call_once()` and
|
|
||||||
// ensure the provided function is only invoked once across all threads. This
|
|
||||||
// type is not copyable or movable. However, it has a `constexpr`
|
|
||||||
// constructor, and is safe to use as a namespace-scoped global variable.
|
|
||||||
class once_flag {
|
|
||||||
public:
|
|
||||||
constexpr once_flag() : control_(0) {}
|
|
||||||
once_flag(const once_flag&) = delete;
|
|
||||||
once_flag& operator=(const once_flag&) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend std::atomic<uint32_t>* base_internal::ControlWord(once_flag* flag);
|
|
||||||
std::atomic<uint32_t> control_;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// End of public interfaces.
|
|
||||||
// Implementation details follow.
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace base_internal {
|
|
||||||
|
|
||||||
// Like call_once, but uses KERNEL_ONLY scheduling. Intended to be used to
|
|
||||||
// initialize entities used by the scheduler implementation.
|
|
||||||
template <typename Callable, typename... Args>
|
|
||||||
void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args);
|
|
||||||
|
|
||||||
// Disables scheduling while on stack when scheduling mode is non-cooperative.
|
|
||||||
// No effect for cooperative scheduling modes.
|
|
||||||
class SchedulingHelper {
|
|
||||||
public:
|
|
||||||
explicit SchedulingHelper(base_internal::SchedulingMode mode) : mode_(mode) {
|
|
||||||
if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
|
|
||||||
guard_result_ = base_internal::SchedulingGuard::DisableRescheduling();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~SchedulingHelper() {
|
|
||||||
if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
|
|
||||||
base_internal::SchedulingGuard::EnableRescheduling(guard_result_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
base_internal::SchedulingMode mode_;
|
|
||||||
bool guard_result_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Bit patterns for call_once state machine values. Internal implementation
|
|
||||||
// detail, not for use by clients.
|
|
||||||
//
|
|
||||||
// The bit patterns are arbitrarily chosen from unlikely values, to aid in
|
|
||||||
// debugging. However, kOnceInit must be 0, so that a zero-initialized
|
|
||||||
// once_flag will be valid for immediate use.
|
|
||||||
enum {
|
|
||||||
kOnceInit = 0,
|
|
||||||
kOnceRunning = 0x65C2937B,
|
|
||||||
kOnceWaiter = 0x05A308D2,
|
|
||||||
// A very small constant is chosen for kOnceDone so that it fit in a single
|
|
||||||
// compare with immediate instruction for most common ISAs. This is verified
|
|
||||||
// for x86, POWER and ARM.
|
|
||||||
kOnceDone = 221, // Random Number
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Callable, typename... Args>
|
|
||||||
ABSL_ATTRIBUTE_NOINLINE
|
|
||||||
void CallOnceImpl(std::atomic<uint32_t>* control,
|
|
||||||
base_internal::SchedulingMode scheduling_mode, Callable&& fn,
|
|
||||||
Args&&... args) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
{
|
|
||||||
uint32_t old_control = control->load(std::memory_order_relaxed);
|
|
||||||
if (old_control != kOnceInit &&
|
|
||||||
old_control != kOnceRunning &&
|
|
||||||
old_control != kOnceWaiter &&
|
|
||||||
old_control != kOnceDone) {
|
|
||||||
ABSL_RAW_LOG(FATAL, "Unexpected value for control word: 0x%lx",
|
|
||||||
static_cast<unsigned long>(old_control)); // NOLINT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // NDEBUG
|
|
||||||
static const base_internal::SpinLockWaitTransition trans[] = {
|
|
||||||
{kOnceInit, kOnceRunning, true},
|
|
||||||
{kOnceRunning, kOnceWaiter, false},
|
|
||||||
{kOnceDone, kOnceDone, true}};
|
|
||||||
|
|
||||||
// Must do this before potentially modifying control word's state.
|
|
||||||
base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode);
|
|
||||||
// Short circuit the simplest case to avoid procedure call overhead.
|
|
||||||
// The base_internal::SpinLockWait() call returns either kOnceInit or
|
|
||||||
// kOnceDone. If it returns kOnceDone, it must have loaded the control word
|
|
||||||
// with std::memory_order_acquire and seen a value of kOnceDone.
|
|
||||||
uint32_t old_control = kOnceInit;
|
|
||||||
if (control->compare_exchange_strong(old_control, kOnceRunning,
|
|
||||||
std::memory_order_relaxed) ||
|
|
||||||
base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
|
|
||||||
scheduling_mode) == kOnceInit) {
|
|
||||||
base_internal::invoke(std::forward<Callable>(fn),
|
|
||||||
std::forward<Args>(args)...);
|
|
||||||
old_control =
|
|
||||||
control->exchange(base_internal::kOnceDone, std::memory_order_release);
|
|
||||||
if (old_control == base_internal::kOnceWaiter) {
|
|
||||||
base_internal::SpinLockWake(control, true);
|
|
||||||
}
|
|
||||||
} // else *control is already kOnceDone
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::atomic<uint32_t>* ControlWord(once_flag* flag) {
|
|
||||||
return &flag->control_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Callable, typename... Args>
|
|
||||||
void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args) {
|
|
||||||
std::atomic<uint32_t>* once = base_internal::ControlWord(flag);
|
|
||||||
uint32_t s = once->load(std::memory_order_acquire);
|
|
||||||
if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
|
|
||||||
base_internal::CallOnceImpl(once, base_internal::SCHEDULE_KERNEL_ONLY,
|
|
||||||
std::forward<Callable>(fn),
|
|
||||||
std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace base_internal
|
|
||||||
|
|
||||||
template <typename Callable, typename... Args>
|
|
||||||
void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) {
|
|
||||||
std::atomic<uint32_t>* once = base_internal::ControlWord(&flag);
|
|
||||||
uint32_t s = once->load(std::memory_order_acquire);
|
|
||||||
if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
|
|
||||||
base_internal::CallOnceImpl(
|
|
||||||
once, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL,
|
|
||||||
std::forward<Callable>(fn), std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ABSL_NAMESPACE_END
|
|
||||||
} // namespace absl
|
|
||||||
|
|
||||||
#endif // ABSL_BASE_CALL_ONCE_H_
|
|
|
@ -1,187 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright 2017 The Abseil Authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// File: casts.h
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This header file defines casting templates to fit use cases not covered by
|
|
||||||
// the standard casts provided in the C++ standard. As with all cast operations,
|
|
||||||
// use these with caution and only if alternatives do not exist.
|
|
||||||
|
|
||||||
#ifndef ABSL_BASE_CASTS_H_
|
|
||||||
#define ABSL_BASE_CASTS_H_
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "absl/base/internal/identity.h"
|
|
||||||
#include "absl/base/macros.h"
|
|
||||||
#include "absl/meta/type_traits.h"
|
|
||||||
|
|
||||||
namespace absl {
|
|
||||||
ABSL_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
namespace internal_casts {
|
|
||||||
|
|
||||||
template <class Dest, class Source>
|
|
||||||
struct is_bitcastable
|
|
||||||
: std::integral_constant<
|
|
||||||
bool,
|
|
||||||
sizeof(Dest) == sizeof(Source) &&
|
|
||||||
type_traits_internal::is_trivially_copyable<Source>::value &&
|
|
||||||
type_traits_internal::is_trivially_copyable<Dest>::value &&
|
|
||||||
std::is_default_constructible<Dest>::value> {};
|
|
||||||
|
|
||||||
} // namespace internal_casts
|
|
||||||
|
|
||||||
// implicit_cast()
|
|
||||||
//
|
|
||||||
// Performs an implicit conversion between types following the language
|
|
||||||
// rules for implicit conversion; if an implicit conversion is otherwise
|
|
||||||
// allowed by the language in the given context, this function performs such an
|
|
||||||
// implicit conversion.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// // If the context allows implicit conversion:
|
|
||||||
// From from;
|
|
||||||
// To to = from;
|
|
||||||
//
|
|
||||||
// // Such code can be replaced by:
|
|
||||||
// implicit_cast<To>(from);
|
|
||||||
//
|
|
||||||
// An `implicit_cast()` may also be used to annotate numeric type conversions
|
|
||||||
// that, although safe, may produce compiler warnings (such as `long` to `int`).
|
|
||||||
// Additionally, an `implicit_cast()` is also useful within return statements to
|
|
||||||
// indicate a specific implicit conversion is being undertaken.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// return implicit_cast<double>(size_in_bytes) / capacity_;
|
|
||||||
//
|
|
||||||
// Annotating code with `implicit_cast()` allows you to explicitly select
|
|
||||||
// particular overloads and template instantiations, while providing a safer
|
|
||||||
// cast than `reinterpret_cast()` or `static_cast()`.
|
|
||||||
//
|
|
||||||
// Additionally, an `implicit_cast()` can be used to allow upcasting within a
|
|
||||||
// type hierarchy where incorrect use of `static_cast()` could accidentally
|
|
||||||
// allow downcasting.
|
|
||||||
//
|
|
||||||
// Finally, an `implicit_cast()` can be used to perform implicit conversions
|
|
||||||
// from unrelated types that otherwise couldn't be implicitly cast directly;
|
|
||||||
// C++ will normally only implicitly cast "one step" in such conversions.
|
|
||||||
//
|
|
||||||
// That is, if C is a type which can be implicitly converted to B, with B being
|
|
||||||
// a type that can be implicitly converted to A, an `implicit_cast()` can be
|
|
||||||
// used to convert C to B (which the compiler can then implicitly convert to A
|
|
||||||
// using language rules).
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// // Assume an object C is convertible to B, which is implicitly convertible
|
|
||||||
// // to A
|
|
||||||
// A a = implicit_cast<B>(C);
|
|
||||||
//
|
|
||||||
// Such implicit cast chaining may be useful within template logic.
|
|
||||||
template <typename To>
|
|
||||||
constexpr To implicit_cast(typename absl::internal::identity_t<To> to) {
|
|
||||||
return to;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bit_cast()
|
|
||||||
//
|
|
||||||
// Performs a bitwise cast on a type without changing the underlying bit
|
|
||||||
// representation of that type's value. The two types must be of the same size
|
|
||||||
// and both types must be trivially copyable. As with most casts, use with
|
|
||||||
// caution. A `bit_cast()` might be needed when you need to temporarily treat a
|
|
||||||
// type as some other type, such as in the following cases:
|
|
||||||
//
|
|
||||||
// * Serialization (casting temporarily to `char *` for those purposes is
|
|
||||||
// always allowed by the C++ standard)
|
|
||||||
// * Managing the individual bits of a type within mathematical operations
|
|
||||||
// that are not normally accessible through that type
|
|
||||||
// * Casting non-pointer types to pointer types (casting the other way is
|
|
||||||
// allowed by `reinterpret_cast()` but round-trips cannot occur the other
|
|
||||||
// way).
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// float f = 3.14159265358979;
|
|
||||||
// int i = bit_cast<int32_t>(f);
|
|
||||||
// // i = 0x40490fdb
|
|
||||||
//
|
|
||||||
// Casting non-pointer types to pointer types and then dereferencing them
|
|
||||||
// traditionally produces undefined behavior.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// // WRONG
|
|
||||||
// float f = 3.14159265358979; // WRONG
|
|
||||||
// int i = * reinterpret_cast<int*>(&f); // WRONG
|
|
||||||
//
|
|
||||||
// The address-casting method produces undefined behavior according to the ISO
|
|
||||||
// C++ specification section [basic.lval]. Roughly, this section says: if an
|
|
||||||
// object in memory has one type, and a program accesses it with a different
|
|
||||||
// type, the result is undefined behavior for most values of "different type".
|
|
||||||
//
|
|
||||||
// Such casting results in type punning: holding an object in memory of one type
|
|
||||||
// and reading its bits back using a different type. A `bit_cast()` avoids this
|
|
||||||
// issue by implementing its casts using `memcpy()`, which avoids introducing
|
|
||||||
// this undefined behavior.
|
|
||||||
//
|
|
||||||
// NOTE: The requirements here are more strict than the bit_cast of standard
|
|
||||||
// proposal p0476 due to the need for workarounds and lack of intrinsics.
|
|
||||||
// Specifically, this implementation also requires `Dest` to be
|
|
||||||
// default-constructible.
|
|
||||||
template <
|
|
||||||
typename Dest, typename Source,
|
|
||||||
typename std::enable_if<internal_casts::is_bitcastable<Dest, Source>::value,
|
|
||||||
int>::type = 0>
|
|
||||||
inline Dest bit_cast(const Source& source) {
|
|
||||||
Dest dest;
|
|
||||||
memcpy(static_cast<void*>(std::addressof(dest)),
|
|
||||||
static_cast<const void*>(std::addressof(source)), sizeof(dest));
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: This overload is only picked if the requirements of bit_cast are
|
|
||||||
// not met. It is therefore UB, but is provided temporarily as previous
|
|
||||||
// versions of this function template were unchecked. Do not use this in
|
|
||||||
// new code.
|
|
||||||
template <
|
|
||||||
typename Dest, typename Source,
|
|
||||||
typename std::enable_if<
|
|
||||||
!internal_casts::is_bitcastable<Dest, Source>::value,
|
|
||||||
int>::type = 0>
|
|
||||||
ABSL_DEPRECATED(
|
|
||||||
"absl::bit_cast type requirements were violated. Update the types "
|
|
||||||
"being used such that they are the same size and are both "
|
|
||||||
"TriviallyCopyable.")
|
|
||||||
inline Dest bit_cast(const Source& source) {
|
|
||||||
static_assert(sizeof(Dest) == sizeof(Source),
|
|
||||||
"Source and destination types should have equal sizes.");
|
|
||||||
|
|
||||||
Dest dest;
|
|
||||||
memcpy(&dest, &source, sizeof(dest));
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
ABSL_NAMESPACE_END
|
|
||||||
} // namespace absl
|
|
||||||
|
|
||||||
#endif // ABSL_BASE_CASTS_H_
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue