我正在尝试获取屏幕或窗口的屏幕截图。我尝试使用X11中的函数 它工作正常。问题是从XImage获取像素需要花费很多时间。 我试图寻找一些关于如何使用openGL做到这一点的答案。这就是我所拥有的:
#include <stdlib.h>
#include <stdio.h>
#include <cstdio>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/Xlib.h>
int main(int argc, char **argv)
{
int width=1200;
int height=800;
//_____________________________----
Display *dpy;
Window root;
GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
XVisualInfo *vi;
GLXContext glc;
dpy = XOpenDisplay(NULL);
if ( !dpy ) {
printf("\n\tcannot connect to X server\n\n");
exit(0);
}
root = DefaultRootWindow(dpy);
vi = glXChooseVisual(dpy, 0, att);
if (!vi) {
printf("\n\tno appropriate visual found\n\n");
exit(0);
}
glXMakeCurrent(dpy, root, glc);
glc = glXCreateContext(dpy, vi, NULL, GL_TRUE);
printf("vendor: %s\n", (const char*)glGetString(GL_VENDOR));
//____________________________________________
glXMakeCurrent(dpy, root, glc);
glEnable(GL_DEPTH_TEST);
GLubyte* pixelBuffer = new GLubyte[sizeof(GLubyte)*width*height*3*3];
glReadBuffer(GL_FRONT);
GLint ReadBuffer;
glGetIntegerv(GL_READ_BUFFER,&ReadBuffer);
glPixelStorei(GL_READ_BUFFER,GL_RGB);
GLint PackAlignment;
glGetIntegerv(GL_PACK_ALIGNMENT,&PackAlignment);
glPixelStorei(GL_PACK_ALIGNMENT,1);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_INT, pixelBuffer);
int i;
for (i=0;i<100;i++) printf("%u\n",((unsigned int *)pixelBuffer)[i]);
return 0;
}
当我运行程序时,它返回一个错误: X请求失败的错误:BadAccess(尝试访问私有资源被拒绝) 失败请求的主要操作码:199() 失败请求的次要操作码:26 失败请求的序列号:20 输出流中的当前序列号:20
如果我用glXMakeCurrent(dpy,root,glc)评论该行;在glc = glXCreateContext之前(dpy,vi,NULL,GL_TRUE);它不返回任何错误,但所有像素都是0。
我应该怎么解决这个问题?我是openGL的新手,也许我在这里缺少一些重要的东西。也许存在从屏幕或特定窗口获取像素的另一种方式?
答案 0 :(得分:7)
我不认为你想做的事情是可能的。您不能使用OpenGL从您不拥有的窗口读取像素,甚至可能不使用OpenGL。你需要坚持使用X11。
如果您有XImage
,则可以从ximage->data
获取原始像素。只要确保你以正确的格式阅读它。
答案 1 :(得分:4)
您可以使用XShmGetImage,但必须先查询X11服务器的扩展名,以确保MIT-SHM扩展名可用。您还需要知道如何为此设置和使用共享内存段。
查询扩展名:
http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavdevice/x11grab.c#l224
获取图片:
http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavdevice/x11grab.c#l537
答案 2 :(得分:0)
以下在我的平台上以140 fps运行一次。 xcb_image_get()
(使用XCB_IMAGE_FORMAT_Z_PIXMAP
调用)将逐个像素地存储ximg->data
中的所有像素。在我的平台上,每个像素为32位,每个通道为8位,并且有3个通道(每个像素不使用8位)。
/*
gcc ss.c -o ss -lxcb -lxcb-image && ./ss
*/
#include <stdio.h>
#include <xcb/xcb_image.h>
xcb_screen_t* xcb_get_screen(xcb_connection_t* connection){
const xcb_setup_t* setup = xcb_get_setup(connection); // I think we don't need to free/destroy this!
return xcb_setup_roots_iterator(setup).data;
}
void xcb_image_print(xcb_image_t* ximg){
printf("xcb_image_print() Printing a (%u,%u) `xcb_image_t` of %u bytes\n\n", ximg->height, ximg->width, ximg->size);
for(int i=0; i < ximg->size; i += 4){
printf(" ");
printf("%02x", ximg->data[i+3]);
printf("%02x", ximg->data[i+2]);
printf("%02x", ximg->data[i+1]);
printf("%02x", ximg->data[i+0]);
}
puts("\n");
}
int main(){
// Connect to the X server
xcb_connection_t* connection = xcb_connect(NULL, NULL);
xcb_screen_t* screen = xcb_get_screen(connection);
// Get pixels!
xcb_image_t* ximg = xcb_image_get(connection, screen->root, 0, 0, screen->width_in_pixels, screen->height_in_pixels, 0xffffffff, XCB_IMAGE_FORMAT_Z_PIXMAP);
// ... Now all pixels are in ximg->data!
xcb_image_print(ximg);
// Clean-up
xcb_image_destroy(ximg);
xcb_disconnect(connection);
}