在Qt中渲染OpenGL场景并将其流式传输到HTML5接口
我想知道是否有可能在Qt中渲染OpenGL场景并将其实时流式传输到HTML5接口(我的意思是场景是在现场生成的) 我一直在努力寻找有关信息,以及如何做到这一点,但我没有成功 如果存在,是否存在任何现有机制来压缩图像和优化带宽。我正在考虑一个类似Citrix的解决方案,但要使用HTML5客户端。嗯 我记得有一个简单但有效的开源项目,但我找不到链接。在这个项目中,视频捕获(或者在您的例子中是窗口缓冲区)被编码为MPEG,并通过WebSocket连接发送到浏览器。然后,客户端Javascript解码该MPEG流并显示它。这个可能会给你更多关于这个主题的信息在Qt中渲染OpenGL场景并将其流式传输到HTML5接口,html,qt,opengl,Html,Qt,Opengl,我想知道是否有可能在Qt中渲染OpenGL场景并将其实时流式传输到HTML5接口(我的意思是场景是在现场生成的) 我一直在努力寻找有关信息,以及如何做到这一点,但我没有成功 如果存在,是否存在任何现有机制来压缩图像和优化带宽。我正在考虑一个类似Citrix的解决方案,但要使用HTML5客户端。嗯 我记得有一个简单但有效的开源项目,但我找不到链接。在这个项目中,视频捕获(或者在您的例子中是窗口缓冲区)被编码为MPEG,并通过WebSocket连接发送到浏览器。然后,客户端Javascript解码该
也许您可以使用具有最佳层的WebSocket,以实现最大的跨浏览器兼容性,从而在Qt应用程序和HTML5客户端之间传输数据 您必须在Qt应用程序中以某种方式对渲染的图片进行编码,并通过套接字将其发送到HTML5客户端,后者将对其进行解码和渲染 Socket.IO在他们的网站上有一个类似的演示。
检查一下 这是完全可以实现的,但这取决于您愿意在多大程度上扩展“实时”的概念。但Qt将帮不了多少忙
- 1-从GPU内存中获取图像。这几乎是Qt可以提供帮助的唯一地方。它提供了两种“开箱即用”的方法,可以对您有所帮助。第一种方法是,如果已将OpenGL渲染合并到
或派生类中的元素中,则可以使用QQuickView
从帧缓冲区获取grabWindow()
。第二种方法是使用提供类似方法的QImage
类,但它可能比第一种方法更慢。在我的系统(相当高端)上,对于720p的分辨率,从GPU内存中获取原始图像大约需要30毫秒,对于较低的分辨率,它以二次速率变得更快。如果您精通OpenGL,您可能需要研究特定于供应商的扩展,这些扩展可能会在将每个渲染帧从GPU复制到CPU内存时提供较少的开销,这就是索尼或nVidia等公司能够实现更好图形流的方式QScreen
- 2-使用FFmpeg将传入的
数据编码为视频(最好是H264),以最小化带宽。您可能想检查一下这一点,这应该是Qt的开箱即用。FFmpeg还可以帮助进行实际操作,无需为此使用额外的库,尽管我不确定如果不使用“中继”服务器对其进行重新流式处理,该流是否可以在HTML播放器中使用QImage
但你不应该期待奇迹。图形流已经在供应商自己的设备上使用他们的专有技术并通过快速的本地网络运行得很糟糕了。在真实场景中,为延迟为半秒或更高的“实时”做好准备。当然,最近有一些努力致力于这一毫无意义的努力,但像许多其他人一样,这只是为了这样做,而不是因为这样做有实际的好处。如果你有一个10 gbit的网络,并且有特殊的GPU硬件可以直接使用它,那么流式图形可能是可行的解决方案,但是这个解决方案将是昂贵和低效的,看看今天消耗2-3瓦功率的10美元芯片如何能够渲染OpenGL,这将永远是最可取的解决方案。既然你提到了HTML5浏览器,那么你很有可能会选择WebGL解决方案,IMO将比流式传输图形更优越,因为WebGL在这一点上很糟糕。更好的是,Qt已经支持大量平台,您可以轻松实现自己的渲染应用程序,获得比WebGL更好的性能,并可能获得更多的渲染功能。此答案解释了如何使用OpenGL、Qt和。但在我开始之前,有两个问题需要立即解决:
- 。我建议使用Ogg进行编码,因为它比h264更受现代浏览器的支持李>
- 如果没有第三方库的帮助,对视频进行编码并将其流式传输到HTTP将是一个相当大的挑战。好好看看(一个处理多媒体文件的跨平台库)。这就是我在这里使用的从OpenGL的帧缓冲区编码和流式传输帧李>
// GLWidget is a class based on QGLWidget.
void GLWidget::paintGL()
{
/* Setup FBO and RBO */
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fb);
glGenFramebuffersEXT(1, &_fb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fb);
glGenRenderbuffersEXT(1, &_color_rb);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _color_rb);
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_BGRA, viewport[2], viewport[3]);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, _color_rb);
/* Draw the scene (with transparency) */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLoadIdentity();
glTranslatef(-2.0f, 0.0f, -7.0f);
glRotatef(45, 1.0f, 1.0f, 0.0f);
_draw_cube();
glLoadIdentity();
glTranslatef(2.0f, 0.0f, -7.0f);
glRotatef(30, 0.5f, 1.0f, 0.5f);
_draw_cube();
glFlush();
/* Retrieve pixels from the framebuffer */
int imgsize = viewport[2] * viewport[3];
std::cout << "* Viewport size: " << viewport[2] << "x" << viewport[3] << std::endl;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glReadBuffer(GL_COLOR_ATTACHMENT0);
unsigned char* pixels = new unsigned char[sizeof(unsigned char) * imgsize * 4];
glReadPixels(0, 0, viewport[2], viewport[3], GL_BGRA, GL_UNSIGNED_BYTE, pixels);
// Use fwrite to dump data:
FILE* fp = fopen("dumped.bin","w");
fwrite(pixels, sizeof(unsigned char) * imgsize * 4, 1, fp);
fclose(fp);
// or use QImage to encode the raw data to jpg:
QImage image((const unsigned char*)pixels, viewport[2], viewport[3], QImage::Format_RGB32);
QImage flipped = image.mirrored();
flipped.save("output2.jpg");
// Disable FBO and RBO
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// Delete resources
glDeleteRenderbuffersEXT(1, &_color_rb);
glDeleteFramebuffersEXT(1, &_fb);
delete[] pixels;
}
第三步也是最后一步是打开一个HTML5页面,该页面是为显示流而精心设计的。此步骤必须在运行gst launch时执行,因此请将下面的代码复制并粘贴到一个文件中,然后在浏览器中打开该页面(我在Chrome上测试过)。页面连接到本地主机端口8080并开始接收流。您可能已经注意到,gst启动
管道将时钟覆盖在原始图像上:
<html>
<title>A simple HTML5 video test</title>
</html>
<body>
<video autoplay controls width=320 height=240>
<source src="http://localhost:8080" type="video/ogg">
You browser doesn't support element <code>video</code>.
</video>
</body>
在它被流化之前
更新:
问题解决了!不需要在磁盘上创建中间文件,就可以使用或*Ogg直接对其进行流式处理。我自由地将FPS限制设置为15,并降低了TheoreNC的标准质量
<html>
<title>A simple HTML5 video test</title>
</html>
<body>
<video autoplay controls width=320 height=240>
<source src="http://localhost:8080" type="video/ogg">
You browser doesn't support element <code>video</code>.
</video>
</body>
gst-launch-1.0.exe -v filesrc location=dumped.bin blocksize=1920000 ! video/x-raw,format=BGRA,width=800,height=600,framerate=1/1 ! videoconvert ! video/x-raw,format=RGB,framerate=1/1 ! videoflip method=vertical-flip ! imagefreeze ! videorate ! video/x-raw,format=RGB,framerate=30/2 ! videoconvert ! clockoverlay shaded-background=true font-desc="Sans 38" ! theoraenc quality=24 ! oggmux ! queue ! tcpserversink host=127.0.0.1 port=8080 sync-method=2
gst-launch-1.0.exe -v filesrc location=dumped.bin blocksize=1920000 ! video/x-raw,format=BGRA,width=800,height=600,framerate=1/1 ! videoconvert ! video/x-raw,format=RGB,framerate=1/1 ! videoflip method=vertical-flip ! videoscale ! video/x-raw,width=400,height=300! imagefreeze ! videorate ! video/x-raw,format=RGB,framerate=30/2 ! videoconvert ! clockoverlay shaded-background=true font-desc="Sans 38" ! theoraenc quality=24 ! oggmux ! tcpserversink host=127.0.0.1 port=8080 sync-method=2