使用openGL进行常规窗口屏幕捕获

时间:2019-04-18 04:11:00

标签: c++ opengl screen-capture wgl

我正在尝试捕获桌面图像。 (所有图像,包括桌面输出到显示器的图像)

使用窗口API(BitBlt或CImageClass)很容易,而且不是我想要的方式。

我想用opengl来做。所以我找到了glReadPixel函数和透明的窗口。

但是它只是读取像素的Windows应用程序屏幕。(另存为bmp文件并检查)

Initialize()

glfwSetErrorCallback(errorCallback);

if (!glfwInit()) {
    std::cerr << "Error: GLFW " << std::endl;
    exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_DEPTH_BITS, 16);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 4);


const int Monitor_count = GetMonitors();

GLwindow = glfwCreateWindow(
    nWidth, // width
    nHeight, // height
    "OpenGL_Test", // window title
    NULL, NULL);
if (!GLwindow) {
    glfwTerminate();
    exit(EXIT_FAILURE);
}
glfwSwapInterval(1);


if (glfwGetWindowAttrib(GLwindow, GLFW_TRANSPARENT_FRAMEBUFFER))
{
    //...
}
glfwSetWindowOpacity(GLwindow, 0.0f);

auto Mode = glfwGetVideoMode(Monitor[0]);   

glfwMakeContextCurrent(GLwindow);   
glfwSetKeyCallback(GLwindow, keyCallback);

glewExperimental = GL_TRUE;                                         
GLenum errorCode = glewInit();

if (GLEW_OK != errorCode) {

    std::cerr << "Error: GLEW - " << glewGetErrorString(errorCode) << std::endl;
    glfwTerminate();
    exit(EXIT_FAILURE);
}
if (!GLEW_VERSION_3_3) {

    std::cerr << "OpenGL 3.3 API is not available." << std::endl;

    glfwTerminate();
    exit(EXIT_FAILURE);
}

glViewport(0, 0, nWidth, nHeight);

glBindFramebuffer(GL_FRAMEBUFFER, 0);

if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
    std::cerr << "Error: " << std::endl;
}

return true;

队伍

while (!glfwWindowShouldClose(GLwindow)) {

    Sleep(10);

    glClearColor(0.0f, 0.3f, 0.3f, 0.5f);
    glClear(GL_COLOR_BUFFER_BIT);

    unsigned char *image = (unsigned char*)malloc(sizeof(unsigned char)*nWidth*nHeight * 3);

       glReadPixels(0, 0, nWidth, nHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, image);
    glfwPollEvents();

}

return true;

Q1。可以使用OPENGL进行桌面捕获(全图像GPU输出)吗?

Q2。如果有Q1的可能,我应该使用FBO和PBO GL_BACK吗?

Q3。如何访问母窗口或GPU适配器? >> GL似乎强烈拒绝这一点。(我不需要任何渲染,只需从GPU读取像素数据(桌面图像。不由我的应用程序渲染。)(如果可能的话……))

有人向我展示链接或想法吗?

2 个答案:

答案 0 :(得分:1)

您要的东西完全超出了OpenGL的范围。 OpenGL被设计为与平台无关的API,供应用程序讨论以抽象方式将内容绘制到帧缓冲区中。 OpenGL没有Windows *,屏幕或桌面的概念。 OpenGL无法在存在此类概念的级别上运行。哎呀,OpenGL甚至都不知道GPU是什么。应该通过特定于平台的机制来初始化OpenGL,以建立一个将实际含义分配给OpenGL API调用的上下文。据我所知,没有办法用帧缓冲区设置OpenGL上下文,该缓冲区的内容将以某种方式对应于Windows(或我知道的任何其他平台)上的桌面。就我的理解而言,这真的没有道理……

要做您想做的事,您将不得不依赖各自的平台特定的API。 Windows上最简单的方法可能是从那里获得整个桌面的HDC和BitBlt。有关更多信息,请参见例如this question。一种更现代的方法是使用DXGI Desktop Duplication API

(*)是的,我知道OpenGL规范确实确实在一些地方谈到了“ windows”。但是只有在谈论它不负责的所有事情时,它才这样做……

答案 1 :(得分:1)

  

我正在尝试捕获桌面图像。 (所有图像,包括桌面输出到显示器的图像)

     

使用窗口API(BitBlt或CImageClass)很容易,而且不是我想要的方式。

但这是应​​该完成的方式。

  

我想用opengl来做。所以我找到了glReadPixel功能

不能。 OpenGL不会“了解”桌面或其他窗口(或实际上根本不是什么窗口)。函数glReadPixels仅适用于使用OpenGL本身绘制的图像。

您不能使用OpenGL来截取屏幕截图!在较旧的计算机上,它似乎可以正常工作,但这只是因为它们的较旧的内存管理才能在您创建新窗口时将其内存从下面的内容中“剪切”,如果您阅读了该内容,则它看起来就像一种截屏的方法。但事实并非如此。