Gtk Gdk/X11屏幕捕获

Gtk Gdk/X11屏幕捕获,gtk,screen,x11,cairo,gdk,Gtk,Screen,X11,Cairo,Gdk,我想写一个程序,连续捕获屏幕,并对图像进行一些修改。完整的测试程序可在以下位置找到: 然而,我遇到了一些问题。我做的第一个实验是使用Gdk根窗口,从中创建一个Cairo上下文,然后使用它的目标作为另一个窗口的源,其中的内容被绘制为: mScreenContext = Gdk::Screen::get_default()->get_root_window()->create_cairo_context() ... context->set_source(mScreenConte

我想写一个程序,连续捕获屏幕,并对图像进行一些修改。完整的测试程序可在以下位置找到:

然而,我遇到了一些问题。我做的第一个实验是使用Gdk根窗口,从中创建一个Cairo上下文,然后使用它的目标作为另一个窗口的源,其中的内容被绘制为:

mScreenContext = Gdk::Screen::get_default()->get_root_window()->create_cairo_context()
...
context->set_source(mScreenContext->get_target(), 0, 0);
context->paint();
这工作得非常好(上面源代码中的变体1)。它只是把整个屏幕拉到另一个窗口。因此,我的下一步是尝试将内容保存到Cairo ImageSurface中,以便对其进行修改:

mImageContext->set_source(mScreenContext->get_target(), 0, 0);
mImageContext->paint();

context->set_source(mImageSurface, 0, 0);
context->paint();
令人惊讶的是,对于Gtk窗口的第一个图形,屏幕被捕获并绘制。不幸的是,之后什么也没有发生,仍然显示初始屏幕。如何解释这种行为?我必须承认,我对这里的基本过程知之甚少,所以也许有人能给我一些提示

使用
Gdk::Pixbuf
的第三种变体产生完全相同的行为:

mScreenBuffer = Gdk::Pixbuf::create(mGdkRootWindow, 0, 0, mScreenWidth, mScreenHeight);
Gdk::Cairo::set_source_pixbuf(context, mScreenBuffer, 0, 0);
context->paint();
最后(变体4)我尝试直接使用
X11

Display *display = XOpenDisplay((char*)0);
XImage *image = XGetImage(display, RootWindow(display, DefaultScreen(display)), 0, 0, mScreenWidth, mScreenHeight, AllPlanes, XYPixmap);

mScreenBuffer = Gdk::Pixbuf::create_from_data((const guint8*)image->data, Gdk::COLORSPACE_RGB, 0, 8, mScreenWidth, mScreenHeight, mScreenWidth);
Gdk::Cairo::set_source_pixbuf(context, mScreenBuffer, 0, 0);
context->paint();

XFree(image);
事实上,这是可行的(虽然我还没有做出任何努力来正确匹配像素格式),但速度太慢了

因此,如果您能提供关于两个Gdk变体的问题是什么和/或如何加快X11方法的任何提示,我将不胜感激。或者可能有人知道一种完全不同的方法来快速捕捉屏幕

不幸的是,我不太熟悉整个主题,但另一个想法是使用基于OpenGL的窗口管理器,在那里我可以直接读取帧缓冲区?这有意义吗


该计划的主要思想是,我有一个投影仪,我不能直接放在墙上。因此,我的想法是捕获屏幕,进行一些双线性变换以说明投影的隐蔽性,然后在另一个窗口中显示修改后的屏幕,该窗口将显示在投影仪上…

XShmGetImage和XShmPutImage比XGetImage和XPutImage快。 在下一个示例中,我创建了两个图像:src和dst。在每次迭代中,我在src中保存一个屏幕截图,然后在dst中呈现它的缩放版本

下图显示了在名为“screencap”的窗口中运行的示例。 在低需求时,它以60 fps的速度运行(如右上角的航站楼所示)。在高需求时,性能可以降至25fps

测试计算机:

Display resolution: 1920x1080
Graphic card: ATI Radeon HD 4200 (integrated)
CPU: AMD Phenom(tm) II X4 945, 3013.85 MHz
Window manager: XFCE 4.12 (compositing off)
Operating system: OpenBSD 5.9
Tested also in Linux (openSUSE Leap 42.1)

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#ifdef_uuuLinux__
#包括
#恩迪夫
//注释下一行,以便在每一帧处忙等待
//#定义睡眠__
#定义第16667帧
#定义期间1000000
#定义名称“screencap”
#定义名称映射“”
#定义BPP4
结构shmimage
{
xshm-shminfo;
XImage*XImage;
unsigned int*data;//将指向图像的BGRA压缩像素
} ;
void initimage(结构shmimage*image)
{
image->ximage=NULL;
image->shminfo.shmaddr=(char*)-1;
}
图像(显示*dsp,结构shmimage*图像)
{
如果(图像->图像)
{
XShmDetach(dsp和图像->shminfo);
XDestroyImage(图像->图像);
image->ximage=NULL;
}
如果(图像->shminfo.shmaddr!=(字符*)-1)
{
shmdt(image->shminfo.shmaddr);
image->shminfo.shmaddr=(char*)-1;
}
}
int createimage(显示*dsp,结构shmimage*图像,int宽度,int高度)
{
//创建共享内存区域
image->shminfo.shmid=shmget(IPC_私有,宽度*高度*BPP,IPC_创建| 0600);
如果(图像->shminfo.shmid==-1)
{
佩罗尔(姓名);
返回false;
}
//将共享内存段映射到此进程的地址空间
image->shminfo.shmaddr=(char*)shmat(image->shminfo.shmid,0,0);
如果(图像->shminfo.shmaddr==(字符*)-1)
{
佩罗尔(姓名);
返回false;
}
image->data=(unsigned int*)image->shminfo.shmaddr;
image->shminfo.readOnly=false;
//标记要删除的共享内存段
//即使此程序崩溃,它也将被删除
shmctl(image->shminfo.shmid,IPC\u RMID,0);
//分配XImage结构所需的内存
image->ximage=XShmCreateImage(dsp,XDefaultVisual(dsp,XDefaultScreen(dsp)),
默认深度(dsp,XDefaultScreen(dsp)),ZPixmap,0,
&图像->shminfo,0,0);
如果(!image->ximage)
{
破坏图像(dsp,图像);
printf(NAME):无法分配XImage结构\n“;
返回false;
}
图像->图像->数据=(字符*)图像->数据;
图像->图像->宽度=宽度;
图像->图像->高度->高度=高度;
//要求X服务器连接共享内存段并进行同步
XShmAttach(dsp和图像->shminfo);
XSync(dsp,假);
返回true;
}
无效getrootwindow(显示*dsp,结构shmimage*图像)
{
XShmGetImage(dsp,XDefaultRootWindow(dsp),图像->ximage,0,0,所有平面);
}
长时间戳()
{
结构时间值电视;
结构时区;
gettimeofday(&tv,&tz);
返回tv.tv_sec*1000000ml+tv.tv_usec;
}
Window createwindow(显示*dsp,整数宽度,整数高度)
{
无符号长掩码=CWBackingStore;
XSetWindowAttributes属性;
attributes.backing_store=不有用;
掩码|=CWBackingStore;
Window Window=XCreateWindow(dsp,DefaultRootWindow(dsp),
0,0,宽度,高度,0,
默认深度(dsp、XDefaultScreen(dsp)),
InputOutput、CopyFromParent、掩码和属性);
XStoreName(dsp、窗口、名称);
XSelectInput(dsp、窗口、StructureNotifyMask);
XMapWindow(dsp,window);
返回窗口;
}
空窗口(显示器*dsp,窗口)
{
XDestroyWindow(dsp,窗口);
}
unsigned int getpixel(结构shmimage*src,结构shmimage*dst,
gcc screencap.c -o screencap -std=c99 -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 -lXext -lm