基于多线程离屏渲染YUV后,通过不同的CPU及笔记本机型测试,发现在Intel显卡下会出现视频闪花屏及绿屏等现象,通过对WebRtc代码模块中Opengl渲染YUV数据部分进行分析,发现在采用随机的双Opengl通道YUV数据渲染。
首先在初始化2组纹理存储空间
//定义6个纹理存储ID
static const GLsizei kNumTextureSets = 2;
static const GLsizei kNumTexturesPerSet = 3;
static const GLsizei kNumTextures = kNumTexturesPerSet * kNumTextureSets;
//初始化纹理储存ID
void VideoPlayRender::initTextures()
{
glGenTextures(kNumTextures, tex_yuv);
for (GLsizei i = 0; i < kNumTextures; i++) {
glBindTexture(GL_TEXTURE_2D, tex_yuv[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
}
}
在YUV数据渲染时分配渲染数据存储空间
void VideoPlayRender::render(int width, int height, uint8_t* dataY, uint8_t* dataU, uint8_t* dataV, size_t strideY, size_t strideU, size_t strideV, uint32_t userId)
{
//查找空闲储存ID
_currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
m_CurYuv[0] = tex_yuv[_currentTextureSet * kNumTexturesPerSet];
m_CurYuv[1] = tex_yuv[_currentTextureSet * kNumTexturesPerSet + 1];
m_CurYuv[2] = tex_yuv[_currentTextureSet * kNumTexturesPerSet + 2];
//清理空间
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|);
//获取绘制窗体
glViewport(0, 0, width, height);
glBindTexture(GL_TEXTURE_2D, m_CurYuv[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, dataY);
glUniform1i(textureUniformY, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_CurYuv[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width >> 1, height >> 1, 0, GL_RED, GL_UNSIGNED_BYTE, dataU);
glUniform1i(textureUniformU, 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, m_CurYuv[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width >> 1, height >> 1, 0, GL_RED, GL_UNSIGNED_BYTE, dataV);
glUniform1i(textureUniformV, 2);
glFlush(); //离屏渲染必须调用,否则会造成视频异常
}
至此完美解决了部分显卡及机型会出现的花屏及绿屏等问题,其中实现的原理为,当YUV视频数据没有及时更新时,采用上一次渲染好的数据提交给系统刷新进行重复绘制即可,当有新的YUV数据到来时,将当前渲染好的GLuint通道ID通过信号发送到主线程,通过系统显示队里显示即可。
特别注意有时候在界面显示时还没有收到YUV数据时,会出现绿屏现象,这需要根据自己的业务场景,在paintGL中对无数据状态进行保护处理。
void GlVideoWidget::paintGL()
{
if (m_isYuvUpdate == false) //还没有YUV数据更新时候,不做重绘处理
{
return;
}
}
本文暂时没有评论,来添加一个吧(●'◡'●)