wayland(wl_shell) + egl + opengles 最简实例

本文详细介绍了如何在Ubuntu 18.04环境下,利用EGL、OpenGLES2.0和wayland的wl_shell接口创建一个最简单的图形渲染程序。首先,确保安装了Weston、OpenGLES2.0和必要的库文件。接着,了解wl_shell窗口管理器接口,并展示了如何编写并编译egl_wayland_demo.c代码实现wayland client。最后,成功运行程序,显示红色三角形,验证了wayland client、egl和opengles2.0的通路已经建立。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

本文主要介绍如何在 linux 下使用 egl + opengles2.0 相关接口渲染一个三角形的 wayland client 最简程序实例
软硬件环境:
硬件:PC
软件:ubuntu18.04, egl1.4 , opengles2.0, weston3.0


一、ubuntu 上相关环境准备

1. ubuntu 上安装 weston

ubuntu上确保已安装weston 程序,如果没有安装,可以使用 sudo apt install weston 命令来安装, 如下图所示
在这里插入图片描述

2. 确定ubuntu 上安装的opengles 版本

可以使用 glxinfo | grep “OpenGL ES” 命令来确定 ubuntu 上的 opengles 版本, 如下图所示, 可以看到我的 ubuntu18.04 上 安装的是 opengles2.0
在这里插入图片描述
如果提示没有安装 glxinfo 程序,可以使用 sudo apt-get install mesa-utils libgles2-mesa-dev 命令来安装,如下图所示
在这里插入图片描述

3. 确定安装的 weston 是否支持 wl_shell 接口

  1. 先运行 weston ,如下图所示,代表weston 运行成功(weston 版本为3.0.0)
    在这里插入图片描述
  2. 运行 weston-info 命令,查看 weston 是否支持 wl_shell
    如下图所示,可以看到当前 ubuntu 上安装的 weston 是支持 wl_shell 接口的
    在这里插入图片描述

二、窗口管理器接口 wl_shell 介绍

  • wl_shell 是Wayland协议早期版本中定义的一种窗口管理器接口
  • wl_shell 提供了一组固定的窗口管理功能,比如创建新窗口、设置窗口标题和边框、调整窗口大小和位置等;
  • wl_shell 的设计相对较简单,适用于基本的窗口管理需求;
  • 由于wl_shell 功能有限,不符合所有窗口管理器的需求,因此在后续的Wayland协议中被 xdg_wm_base 取代,从2023.5.19 Ubuntu 22.04.2 LTS开始,wl_shell 就被废弃了;

二、代码实例

1.egl_wayland_demo.c

egl_wayland_demo.c 代码如下,其实质就是一个wayland client(weston 是一个wayland server)

#include <wayland-client.h>
#include <wayland-server.h>
#include <wayland-egl.h>
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define WIDTH 640
#define HEIGHT 480

struct window {
   
    struct wl_display *display;
    struct wl_compositor *compositor;
    struct wl_shell *shell;
    struct wl_registry *registry;
    struct wl_surface *surface;
    struct wl_shell_surface *shell_surface;
    struct wl_egl_window *egl_window;
};

// Index to bind the attributes to vertex shaders
const unsigned int VertexArray = 0;

/*for registry listener*/
static void registry_add_object(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) 
{
   
    struct window *window = (struct window *)data;

    if (!strcmp(interface, "wl_compositor")) {
   
        window->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
    } else if(!strcmp(interface, "wl_shell")) {
   
        window->shell = wl_registry_bind(registry, name, &wl_shell_interface, 1);
    } 
}

void registry_remove_object(void *data, struct wl_registry *registry, uint32_t name) 
{
   

}

static struct wl_registry_listener registry_listener = {
   registry_add_object, registry_remove_object};



/*for shell surface listener*/

static void shell_surface_ping (void *data, struct wl_shell_surface *shell_surface, uint32_t serial) 
{
   
	wl_shell_surface_pong (shell_surface, serial);
}

static void shell_surface_configure (void *data, struct wl_shell_surface *shell_surface, uint32_t edges, int32_t width, int32_t height) {
   
	struct window *window = (struct window *)
<think>嗯,用户的问题是关于如何在Linux系统下使用EGLWayland、OpenGL和GStreamer来实现将OpenGL渲染的图像通过GStreamer传输到远端播放,并且要求使用共享上下文的方式。这看起来涉及到多个技术的整合,需要仔细分析每个组件的作用和它们之间的协作方式。 首先,我需要确认各个组件的基本功能和它们如何交互。EGL是用于管理OpenGL上下文和窗口系统(如Wayland)之间的接口。Wayland作为显示服务器协议,替代了传统的X11,负责处理窗口管理和显示。OpenGL负责图形渲染,而GStreamer则处理多媒体数据的流传输,比如编码和网络传输。 用户提到要使用共享上下文的方式,这意味着OpenGL和GStreamer需要共享同一个EGL上下文,这样在渲染后的图像数据可以直接被GStreamer访问,而不需要额外的拷贝,提高效率。这可能涉及到EGLImage和DMABUF的使用,以便在不同的组件之间共享纹理数据。 接下来,我需要考虑如何将OpenGL渲染的结果传递给GStreamer的管道。GStreamer的appsrc是一个常用的源插件,用于将应用程序生成的数据推送到管道中。结合共享上下文,可能需要使用如waylandsink或自定义的插件来处理Wayland的显示,但用户的需求是传输到远端,所以可能需要编码(如H.264)和网络传输(如RTP)。 代码结构方面,大概需要以下几个步骤: 1. 初始化WaylandEGL,创建OpenGL上下文。 2. 创建共享的EGL上下文或资源,使得GStreamer可以访问OpenGL渲染的图像。 3. 设置GStreamer管道,包含appsrc、编码器、网络传输插件等。 4. 在OpenGL渲染循环中,将渲染后的帧导出到GStreamer的管道中进行处理和发送。 需要注意的是,共享上下文可能需要使用EGL的扩展功能,如EGL_KHR_image_base和EGL_WL_create_wayland_buffer_from_image,以便将OpenGL纹理转换为Wayland的缓冲区,再通过GStreamer处理。同时,确保数据格式(如DMA-BUF)的正确性,以便GStreamer能够正确解析。 可能遇到的挑战包括内存管理和同步问题,确保在OpenGL渲染完成后,GStreamer能够安全地访问这些数据而不会出现竞争条件。此外,编码器的配置和网络传输的设置也需要正确,以确保远端播放的流畅性和低延迟。 需要验证各个组件的兼容性,例如GStreamer是否支持Wayland的显示服务器,以及是否安装了必要的插件(如vaapi、x264等)。在代码实现中,可能需要处理错误检查和资源释放,以避免内存泄漏。 后,测试整个流程,确保图像能够正确渲染并通过GStreamer传输到远端设备播放。可能需要使用工具如GStreamer的命令行工具(gst-launch-1.0)来验证接收端的配置是否正确。</think>好的!我将分步骤为您解释如何使用EGL+Wayland+OpenGL+GStreamer实现共享上下文的视频传输方案。以下是关键技术点说明和示例代码框架: --- ### **核心架构说明** 1. **EGL**:管理OpenGL与窗口系统(Wayland)的接口 2. **Wayland**:作为显示服务器协议 3. **OpenGL**:负责图形渲染 4. **GStreamer**:通过共享上下文获取OpenGL渲染结果并进行流传输 --- ### **关键代码结构示例(C语言)** ```c #include <wayland-client.h> #include <EGL/egl.h> #include <gst/gst.h> #include <GLES3/gl3.h> // Wayland全局对象 struct wl_display *display; struct wl_compositor *compositor; struct wl_surface *surface; // EGL相关对象 EGLDisplay egl_display; EGLContext egl_context; EGLSurface egl_surface; // GStreamer管道 GstElement *pipeline; GstElement *appsrc; // 共享资源 EGLImageKHR egl_image; GLuint texture_id; //------------------------------------------ // Wayland+EGL初始化 //------------------------------------------ void init_wayland_egl() { // 1. 连接Wayland服务器 display = wl_display_connect(NULL); // 2. 获取compositor接口 struct wl_registry *registry = wl_display_get_registry(display); wl_registry_add_listener(registry, &registry_listener, NULL); wl_display_roundtrip(display); // 3. 初始化EGL egl_display = eglGetDisplay(display); eglInitialize(egl_display, NULL, NULL); // 4. 配置EGL上下文 const EGLint attribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; EGLConfig config; eglChooseConfig(egl_display, attribs, &config, 1, &config_count); // 5. 创建共享上下文 egl_context = eglCreateContext(egl_display, config, EGL_NO_CONTEXT, NULL); // 6. 创建Wayland窗口表面 surface = wl_compositor_create_surface(compositor); struct wl_egl_window *egl_window = wl_egl_window_create(surface, 1280, 720); egl_surface = eglCreateWindowSurface(egl_display, config, egl_window, NULL); } //------------------------------------------ // GStreamer初始化(共享上下文) //------------------------------------------ void init_gstreamer() { gst_init(NULL, NULL); // 创建管道(示例:H.264编码+RTP传输) pipeline = gst_parse_launch( "appsrc name=gl_src ! videoconvert ! x264enc ! rtph264pay ! udpsink host=127.0.0.1 port=5000", NULL ); appsrc = gst_bin_get_by_name(GST_BIN(pipeline), "gl_src"); // 配置共享内存传输 g_object_set(appsrc, "caps", gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "RGBA", "width", G_TYPE_INT, 1280, "height", G_TYPE_INT, 720, "framerate", GST_TYPE_FRACTION, 30, 1, NULL), "is-live", TRUE, NULL); } //------------------------------------------ // OpenGL渲染循环 //------------------------------------------ void render_frame() { eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); // 1. OpenGL渲染操作 glClear(GL_COLOR_BUFFER_BIT); // ... 实际渲染代码 // 2. 创建EGLImage共享数据 EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; egl_image = eglCreateImageKHR( egl_display, egl_context, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(uintptr_t)texture_id, attribs ); // 3. 通过GStreamer传输 GstBuffer *buffer = gst_buffer_new_wrapped_full( GST_MEMORY_FLAG_READONLY, (gpointer)(uintptr_t)egl_image, // 共享内存指针 1280*720*4, // 数据大小 0, 1280*720*4, // 偏移量和尺寸 NULL, NULL ); gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer); // 4. 交换缓冲区 eglSwapBuffers(egl_display, egl_surface); } //------------------------------------------ // 主函数 //------------------------------------------ int main() { init_wayland_egl(); init_gstreamer(); gst_element_set_state(pipeline, GST_STATE_PLAYING); while (1) { render_frame(); usleep(33333); // ~30fps } return 0; } ``` --- ### **关键实现细节** 1. **共享上下文**:通过`eglCreateImageKHR`创建EGLImage共享纹理 2. **内存传递**:使用`gst_buffer_new_wrapped_full`将EGLImage包装为GStreamer缓冲区 3. **格式匹配**:确保OpenGL纹理格式与GStreamer的`video/x-raw`格式对齐 4. **同步机制**:需要添加帧同步控制,避免缓冲区竞争 --- ### **编译依赖** ```bash # 编译命令示例 gcc main.c -o demo \ $(pkg-config --cflags --libs wayland-client egl glesv2) \ $(pkg-config --cflags --libs gstreamer-1.0 gstreamer-app-1.0) ``` --- ### **潜在问题优化** 1. **DMA-BUF支持**:现代系统建议使用`DMABuf`进行零拷贝传输 2. **EGL扩展检查**:运行时需要验证`EGL_KHR_image_base`扩展是否可用 3. **线程安全**:渲染线程与GStreamer推送线程需要同步 需要根据实际运行环境调整具体参数,建议使用GStreamer调试工具(如`GST_DEBUG=3`)排查问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值