Linux上使用opengl跨线程绘制yuv图像

     在 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. 绘制效果如下:

Linux上使用opengl跨线程绘制yuv图像_第1张图片

Linux上使用opengl跨线程绘制yuv图像_第2张图片

     我主要是测试opengl在x window上的运行情况,只拉了一路rtmp直播流,然后将这一路的yuv图像用作三个X子窗口绘制(三个线程调用opengl绘制同一个yuv图像).

     测试下来效果还不错,和我的windows直播播放器一样流畅, 延时也非常底, 当然整个开发过程中也遇到不少问题,基本上都能找到一个解决方案,无需一些特殊workaround。这里是直接用xlib开发基本的demo,使用QT之类的UI框架应该也可以,更多问题可以联系qq: 1130758427, qq群: 294891451 182979815.  github

你可能感兴趣的:(直播播放器,rtmp播放,低延时rtsp播放,glx,linux,opengl,linux,gl,yuv,linux直播播放器,linux,rtmp直播播放器)