in development

This commit is contained in:
Oleg Shishlyannikov 2025-12-16 06:13:17 +03:00
parent 88a35b2316
commit caa465a3eb
3 changed files with 164 additions and 16 deletions

View File

@ -1,20 +1,25 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <linux/input-event-codes.h>
#include <linux/uinput.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/time.h>
#include <unistd.h>
#include <wayland-client-protocol.h>
#include <wayland-util.h>
#include <msgpack.h>
#include "glib-object.h"
#include "glib.h"
#include "gst/gstbuffer.h"
#include "gst/gstinfo.h"
#include "gst/gstobject.h"
#include "gst/gstparamspecs.h"
#include "gst/gstvalue.h"
#include "gst/video/video-format.h"
@ -36,10 +41,7 @@ enum {
N_PROPERTIES,
};
static GParamSpec *properties[N_PROPERTIES] = {
NULL,
};
// Gstreamer related
static gboolean gst_westonimagesrc_start(GstBaseSrc *basesrc);
static gboolean gst_westonimagesrc_stop(GstBaseSrc *basesrc);
static GstFlowReturn gst_westonimagesrc_create(GstBaseSrc *basesrc, guint64 offset, guint size, GstBuffer **buf);
@ -55,6 +57,7 @@ static gboolean gst_westonimagesrc_negotiate(GstBaseSrc *basesrc);
G_DEFINE_TYPE(GstWestonImageSrc, gst_westonimagesrc, GST_TYPE_BASE_SRC);
// Weston related
static void weston_display_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, int width, int height, int refresh);
static void weston_display_handle_geometry(void *data, struct wl_output *wl_output, int x, int y, int physical_width, int physical_height, int subpixel, const char *make,
const char *model, int transform);
@ -65,12 +68,159 @@ static void weston_handle_global_remove(void *data, struct wl_registry *registry
static void weston_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { /* XXX: unimplemented */ }
static struct wl_buffer *weston_screenshot_create_shm_buffer(int width, int height, void **data_out, struct wl_shm *shm);
static int weston_screenshot_set_buffer_size(struct buffer_size *buff_size, struct wl_list *output_list);
static void weston_capture_frame();
static const struct wl_output_listener output_listener = {weston_display_handle_geometry, weston_display_handle_mode};
static const struct weston_screenshooter_listener screenshooter_listener = {weston_screenshot_done};
static const struct wl_registry_listener registry_listener = {weston_handle_global, weston_handle_global_remove};
// Remote control
static void rcontrol_init(GstWestonImageSrc *westonimagesrc);
static void rcontrol_init_uinput(GstWestonImageSrc *westonimagesrc);
static void rcontrol_init_server(GstWestonImageSrc *westonimagesrc);
static gpointer rcontrol_listener_thread(gpointer data);
static void rcontrol_destroy(GstWestonImageSrc *westonimagesrc);
static void rcontrol_emit(GstWestonImageSrc *westonimagesrc, int fd, int type, int code, int value);
static void rcontrol_emit(GstWestonImageSrc *westonimagesrc, int fd, int type, int code, int value) {
struct input_event ev;
memset(&ev, 0, sizeof(ev));
gettimeofday(&ev.time, NULL);
ev.type = type;
ev.code = code;
ev.value = value;
if (write(fd, &ev, sizeof(ev)) < 0) {
GST_WARNING_OBJECT(westonimagesrc, "write() input_event %i:%i:%i:%i failed", fd, type, code, value);
}
}
static void rcontrol_init(GstWestonImageSrc *westonimagesrc) {
rcontrol_init_uinput(westonimagesrc);
rcontrol_init_server(westonimagesrc);
}
static gpointer rcontrol_listener_thread(gpointer data) {
const uint16_t port = 7755u;
GstWestonImageSrc *westonimagesrc = data;
g_mutex_lock(&westonimagesrc->lock);
westonimagesrc->udp_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (westonimagesrc->udp_socket_fd < 0) {
GST_WARNING_OBJECT(westonimagesrc, "socket() UDP socket creation failed");
return NULL;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(westonimagesrc->udp_socket_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
GST_ERROR_OBJECT(westonimagesrc, "bind() UDP socket binding failed");
close(westonimagesrc->udp_socket_fd);
return NULL;
}
GST_INFO_OBJECT(westonimagesrc, "UDP listener started on port %d\n", port);
g_mutex_unlock(&westonimagesrc->lock);
char buf[1024u];
msgpack_zone mempool;
msgpack_zone_init(&mempool, sizeof(buf));
while (TRUE) {
struct sockaddr_in src;
socklen_t srclen = sizeof(src);
ssize_t len = recvfrom(westonimagesrc->udp_socket_fd, buf, sizeof(buf) - 1, 0, (struct sockaddr *)&src, &srclen);
if (len < 0) {
GST_WARNING_OBJECT(westonimagesrc, "recvfrom() failed");
continue;
}
buf[len] = '\0';
msgpack_object deserialized;
msgpack_unpack(buf, sizeof(buf), NULL, &mempool, &deserialized);
GST_INFO_OBJECT(westonimagesrc, "[UDP %s:%d]: %s\r\n", inet_ntoa(src.sin_addr), ntohs(src.sin_port), deserialized.via.str.ptr);
}
close(westonimagesrc->udp_socket_fd);
return NULL;
}
static void rcontrol_init_server(GstWestonImageSrc *westonimagesrc) {
g_mutex_lock(&westonimagesrc->lock);
westonimagesrc->listener_thread = g_thread_new("UDP listener thread", rcontrol_listener_thread, westonimagesrc);
g_mutex_unlock(&westonimagesrc->lock);
}
static void rcontrol_init_uinput(GstWestonImageSrc *westonimagesrc) {
struct uinput_user_dev uud;
g_mutex_lock(&westonimagesrc->lock);
westonimagesrc->uinput_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (westonimagesrc->uinput_fd < 0) {
GST_ERROR_OBJECT(westonimagesrc, "open() /dev/uinput failed");
return;
}
// Init keyboard
{
ioctl(westonimagesrc->uinput_fd, UI_SET_EVBIT, EV_KEY);
for (int key = KEY_ESC; key <= KEY_MICMUTE; key++) {
ioctl(westonimagesrc->uinput_fd, UI_SET_KEYBIT, key);
}
}
// Init mouse
{
// Mouse events
ioctl(westonimagesrc->uinput_fd, UI_SET_EVBIT, EV_REL);
// Mouse buttons
ioctl(westonimagesrc->uinput_fd, UI_SET_KEYBIT, BTN_LEFT);
ioctl(westonimagesrc->uinput_fd, UI_SET_KEYBIT, BTN_RIGHT);
ioctl(westonimagesrc->uinput_fd, UI_SET_KEYBIT, BTN_MIDDLE);
// Mouse rels
ioctl(westonimagesrc->uinput_fd, UI_SET_RELBIT, REL_X);
ioctl(westonimagesrc->uinput_fd, UI_SET_RELBIT, REL_Y);
ioctl(westonimagesrc->uinput_fd, UI_SET_RELBIT, REL_WHEEL);
ioctl(westonimagesrc->uinput_fd, UI_SET_RELBIT, REL_HWHEEL);
}
// Init device
struct uinput_setup usetup;
memset(&usetup, 0, sizeof(usetup));
snprintf(usetup.name, UINPUT_MAX_NAME_SIZE, "Virtual Keyboard + Mouse");
usetup.id.bustype = BUS_USB;
usetup.id.vendor = 0x7777;
usetup.id.product = 0x8888;
usetup.id.version = 1;
ioctl(westonimagesrc->uinput_fd, UI_SET_EVBIT, EV_SYN);
if (ioctl(westonimagesrc->uinput_fd, UI_DEV_SETUP, &usetup) < 0) {
GST_ERROR_OBJECT(westonimagesrc, "ioctl() UI_DEV_SETUP failed");
return;
}
if (ioctl(westonimagesrc->uinput_fd, UI_DEV_CREATE) < 0) {
GST_ERROR_OBJECT(westonimagesrc, "ioctl() UI_DEV_CREATE failed");
return;
}
g_mutex_unlock(&westonimagesrc->lock);
}
static void rcontrol_destroy(GstWestonImageSrc *westonimagesrc) {
ioctl(westonimagesrc->uinput_fd, UI_DEV_DESTROY);
close(westonimagesrc->uinput_fd);
}
static int weston_screenshot_set_buffer_size(struct buffer_size *buff_size, struct wl_list *output_list) {
struct screenshooter_output *output;
buff_size->min_x = buff_size->min_y = INT_MAX;
@ -234,6 +384,8 @@ static void gst_westonimagesrc_init(GstWestonImageSrc *westonimagesrc) {
GST_INFO_OBJECT(westonimagesrc, "Creating shared mem buffer ...");
output->buffer = weston_screenshot_create_shm_buffer(output->width, output->height, &output->data, sh_data.shm);
}
rcontrol_init(westonimagesrc);
}
static GstCaps *gst_westonimagesrc_get_caps(GstBaseSrc *src, GstCaps *filter) {
@ -318,16 +470,6 @@ static gboolean gst_westonimagesrc_stop(GstBaseSrc *basesrc) {
return TRUE;
}
static void weston_capture_frame() {
wl_list_for_each(output, &sh_data.output_list, link) {
weston_screenshooter_shoot(sh_data.screenshooter, output->output, output->buffer);
sh_data.buffer_copy_done = 0;
while (!sh_data.buffer_copy_done)
wl_display_roundtrip(display);
}
}
static GstFlowReturn gst_westonimagesrc_create(GstBaseSrc *basesrc, guint64 offset, guint size, GstBuffer **buf) {
GstWestonImageSrc *src = GST_WESTONIMAGESRC(basesrc);
GstBuffer *buffer;

View File

@ -19,6 +19,7 @@
#include <wayland-util.h>
#include "config.h"
#include "glib.h"
#include "weston-screenshooter-client-protocol.h"
#include "shared/os-compatibility.h"
#include "shared/xalloc.h"
@ -61,6 +62,10 @@ struct _GstWestonImageSrc {
guint64 frame_number;
gboolean do_timestamp;
// Remote control
gint uinput_fd, udp_socket_fd;
GThread *listener_thread;
// Stat
GstClockTime last_timestamp;
};

View File

@ -368,6 +368,7 @@ if get_option('shell-desktop')
gstvideo_dep = dependency('gstreamer-video-1.0', version : '>=1.18',
fallback : ['gstreamer', 'gstvideo_dep'])
msgpack_dep = dependency('msgpack-c')
gst_westonimagesrc_plugin_c_args = ['-DHAVE_CONFIG_H']
gst_westonimagesrc_cdata = configuration_data()
@ -390,7 +391,7 @@ if get_option('shell-desktop')
weston_screenshooter_protocol_c,
include_directories: common_inc,
c_args: gst_westonimagesrc_plugin_c_args,
dependencies : [gst_dep, gstbase_dep, gstvideo_dep, dep_toytoolkit],
dependencies : [gst_dep, gstbase_dep, gstvideo_dep, dep_toytoolkit, msgpack_dep],
install : true,
install_dir : plugins_install_dir,
)