首页 > *nix技术 > Xcb-Damage扩展

Xcb-Damage扩展

2022年11月12日 发表评论 阅读评论 142 次浏览

一,Windows截屏变化区域

https://www.pianshen.com/article/1554879856/

https://blog.csdn.net/qwerty448/article/details/53056576

windows8以上的系统,则实现了一个DXGI,用来截取桌面,它是集成在DirectX之中,成为DX的一个子功能。
你需要简单熟悉DirectX技术才能使用DXGI,他通过一堆啰嗦的创建和查询各种接口,最终获取到IDXGIOutputDuplication接口。
截屏的时候,使用这个接口的AcquireNextFrame函数获取当前桌面图像,当然这个接口还提供GetFrameDirtyRects等函数获取发生了变化的矩形区域。

从上面描述可以看到,Windows有个名为IDXGIOutputDuplication::GetFrameDirtyRects的API接口,可以捕获发生变化的桌面区域,这对桌面的远程接入有很大帮助,可以减少桌面图像流量。

二,Linux截屏变化区域
X11下找到一个damage扩展,应该是与桌面变化区域相关的功能。

https://www.x.org/releases/X11R7.7/doc/damageproto/damageproto.txt

https://www.x.org/releases/X11R7.7/doc/index.html

https://www.x.org/releases/current/doc/man/man3/xcb_damage_create.3.xhtml

https://www.x.org/releases/current/doc/man/man3/

https://xcb.freedesktop.org/manual/group__XCB__Damage__API.html

https://gitlab.freedesktop.org/xorg/lib/libxdamage

https://github.com/freedesktop

0,测试环境
硬件:VirtualBox 7.0
操作系统:UbuntuKylin 20.04.3 LTS

1,在这里找到一份damage的相关测试代码,试试:

https://forum.kde.org/viewtopic.php?t=132167

// filename: main.c

#include <cstring>
#include <iostream>
#include <memory>

#include <sys/select.h>

#include <xcb/xcb.h>
#include <xcb/xcb_event.h>
#include <xcb/damage.h>

using namespace std;

struct xcb_connection_deleter
{
    void operator()(xcb_connection_t* c)
    {
        if (c)
        {
            xcb_disconnect(c);
        }
    }
};

xcb_screen_t* screen_of_display(xcb_connection_t* c, int screen)
{
    for (auto iter = xcb_setup_roots_iterator(xcb_get_setup(c)); iter.rem; --screen, xcb_screen_next(&iter))
    {
        if (screen == 0)
        {
            return iter.data;
        }
    }
    return nullptr;
}

int main()
{
    unique_ptr<xcb_connection_t, xcb_connection_deleter> connection{xcb_connect(nullptr, nullptr)};
    int rc = xcb_connection_has_error(connection.get());
    if (rc != 0)
    {
        cout << "xcb connection error: " << rc << endl;
        exit(1);
    }

    const auto extreply = xcb_get_extension_data(connection.get(), &xcb_damage_id);
    if (!extreply->present)
    {
        cout << "xcb-damage is not present\n";
        exit(1);
    }

    uint8_t damageEvent = extreply->first_event;
    auto cookie = xcb_damage_query_version(connection.get(), XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION);
    xcb_generic_error_t* e = 0;
    auto reply = xcb_damage_query_version_reply(connection.get(), cookie, &e);
    if (!reply)
    {
        cout << "xcb_damage_use_extension error: " << e->error_code << endl;
        exit(1);
    }
    free(reply);

    auto damage_handle = xcb_generate_id(connection.get());
    xcb_damage_create(connection.get(), damage_handle, screen_of_display(connection.get(), 0)->root, XCB_DAMAGE_REPORT_LEVEL_RAW_RECTANGLES);

    xcb_flush(connection.get());

    auto xfd = xcb_get_file_descriptor(connection.get());
    if (xfd <= 0)
    {
        cout << "invalid xcb file descriptor\n";
        exit(1);
    }

    while (1)
    {
        auto tv = timeval{0, 20000};
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(xfd, &fds);

        int result = select(xfd + 1, &fds, nullptr, nullptr, &tv);
        if (result == 0)
        {
            continue;
        } else if (result < 0) {
            cerr << "select failed with error: " << strerror(errno) << endl;
            exit(1);
        }

        xcb_generic_event_t* event;
        while ((event = xcb_poll_for_event(connection.get())))
        {
            if (XCB_EVENT_RESPONSE_TYPE(event) != damageEvent)
            {
                free(event);
                continue;
            }
            auto d = reinterpret_cast<xcb_damage_notify_event_t&>(*event);
            cout << "--------- damage event ----------" << endl;
            cout << "area:     x: " << d.area.x << ", y: " << d.area.y << ", w: " << d.area.width << ", h: " << d.area.height << endl;
            cout << "geometry: x: " << d.geometry.x << ", y: " << d.geometry.y << ", w: " << d.geometry.width << ", h: " << d.geometry.height << endl;
            free(event);
        }
    }
    xcb_damage_destroy(connection.get(), damage_handle);
           
    return 0;
}

2,编译
$ sudo apt install g++
$ sudo apt install libx11-xcb-dev
$ sudo apt install libxcb-util-dev
$ sudo apt install libxcb-damage0-dev
$ $ g++ main.c -o demo -lxcb -lxcb-damage -O0 -g

3,运行
在远程ssh终端里执行,显示如下:
$ ./demo
——— damage event ———-
area: x: 0, y: 0, w: 1366, h: 768
geometry: x: 0, y: 0, w: 1366, h: 768
^C

在VirtualBox本地桌面里操作,demo没有动静,应该是代码里抓的屏幕不对。
修改下代码:
将:xcb_connect(nullptr, nullptr)
改为:xcb_connect(“:0.0″, nullptr)

再编译执行:
$ ./demo
——— damage event ———-
area: x: 0, y: 0, w: 1360, h: 768
geometry: x: 0, y: 0, w: 1360, h: 768
——— damage event ———-
area: x: 0, y: 0, w: 1360, h: 768
geometry: x: 0, y: 0, w: 1360, h: 768
——— damage event ———-
area: x: 0, y: 0, w: 1360, h: 768
geometry: x: 0, y: 0, w: 1360, h: 768
——— damage event ———-
area: x: 10, y: 8, w: 90, h: 100
geometry: x: 0, y: 0, w: 1360, h: 768
——— damage event ———-
area: x: 10, y: 8, w: 90, h: 100
geometry: x: 0, y: 0, w: 1360, h: 768
——— damage event ———-
area: x: 10, y: 114, w: 90, h: 100
geometry: x: 0, y: 0, w: 1360, h: 768

就能正常获取到所有在VirtualBox本地桌面里操作的改变区域了。

over~

参考:

https://linux.tutorialink.com/xcb_poll_for_event-causes-100-usage-of-one-cpu-core/

https://www.itcodet.com/cpp/cpp-xcb_poll_for_event-function-examples.html

转载请保留地址:http://www.lenky.info/archives/2022/11/3227http://lenky.info/?p=3227


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。

分类: *nix技术 标签: ,
  1. 本文目前尚无任何评论.
您必须在 登录 后才能发布评论.