在 X Window上使用opengl绘制yuv图像需要用GLX, glx相关资料和接口说明网上都能找到. opengl想直接绘制yuv图像的话,需要Linux系统和显卡驱动支持较高版本的opengl, 也就是说opengl需要支持可编程渲染管线,然后写个顶点shader和片元shader。另外我的使用场景需要单独的线程调用opengl做绘制。
下面看看具体实现:
1. 使用Xlib之前需要调用XInitThreads(); 让Xlib支持多线程. 可以在程序刚启动时就调用,代码如下:
int main(int argc, char *argv[])
{
XInitThreads();
// 其他代码
return 0;
}
QT也有相关的选项去调用XInitThreads();
2. 为了使用多线程,先创建了一个主的X窗口和四个X子窗口:
auto main_wid = XCreateSimpleWindow(display, root, 0, 0, main_w, main_h, 0, white_pixel, black_pixel);
XSelectInput(display, main_wid, StructureNotifyMask | KeyPressMask);
CreateSubWindows(display, screen, root, main_wid, gl_vi, gl_renders);
3. 为了方便测试,主X窗口大小变化时,四个子窗口也重新布局,监听ConfigureNotify事件:
if (xev.type == ConfigureNotify)
{
if (xev.xconfigure.window == main_wid)
{
if (xev.xconfigure.width != main_w || xev.xconfigure.height != main_h)
{
main_w = xev.xconfigure.width;
main_h = xev.xconfigure.height;
bool is_layout = false;
std::vector layouts;
GetSubWindowsLayout(xev.xconfigure.width, xev.xconfigure.height,
g_border_width, gl_renders.size(), layouts, is_layout);
if ( is_layout )
{
auto iter_layout = layouts.begin();
for (auto& i : gl_renders)
{
XMoveResizeWindow(display, i->window_, iter_layout->x_,
iter_layout->y_, iter_layout->width_, iter_layout->height_);
++iter_layout;
}
}
}
}
4. 给每一个子窗口创建一个opengl绘制线程, 需要注意的就是每个绘制线程需要关联一个gl context,说白了就是opengl的操作需要有一个gl context, 代码如下:
// 启动线程
for (auto& i : gl_renders)
{
assert(i);
i->Start();
}
// 绘制线程代码
void yuv_render:run()
{
assert(!context_);
context_ = glXCreateContext(GetDisplay(), vi_, NULL, True);
if (!context_)
{
// log(xxxx)
return;
}
glXMakeCurrent(GetDisplay(), window_, context_);
glViewport(0, 0, viewport_width_, viewport_height_);
CreateYUVShader();
InitYUVTextures();
while(!is_exit)
{
yuv_event.wait(100);
UpdateViewport();
UpdateYUVTextures();
Draw();
glXSwapBuffers(GetDisplay(), window_);
}
// 后续清理工作
}
6. 绘制效果如下:
我主要是测试opengl在x window上的运行情况,只拉了一路rtmp直播流,然后将这一路的yuv图像用作三个X子窗口绘制(三个线程调用opengl绘制同一个yuv图像).
测试下来效果还不错,和我的windows直播播放器一样流畅, 延时也非常底, 当然整个开发过程中也遇到不少问题,基本上都能找到一个解决方案,无需一些特殊workaround。这里是直接用xlib开发基本的demo,使用QT之类的UI框架应该也可以,更多问题可以联系qq: 1130758427, qq群: 294891451 182979815. github