Compare commits

..

11 Commits

Author SHA1 Message Date
Andri Yngvason 16c916510f h264-v4l2m2m: Remove bogus cleanup 2024-03-17 13:14:51 +00:00
Andri Yngvason 14a95b8620 h264-v4l2m2m: Implement key-frame coercion 2024-03-17 10:15:38 +00:00
Andri Yngvason fe3dc26441 h264-v4l2m2m: Add timestamp to source buffers 2024-03-17 10:14:53 +00:00
Andri Yngvason beb62a032f h264-encoder: Try v4l2 before ffmpeg 2024-03-16 22:33:54 +00:00
Andri Yngvason d28b2576e9 h264-v4l2m2m: Scan for capable v4l2 device 2024-03-16 22:33:54 +00:00
Andri Yngvason 6d8645d6e9 h264-v4l2m2m: Align buffer size up to nearest multiple of 16 2024-03-16 22:33:54 +00:00
Andri Yngvason 87b308f15f h264-v4l2m2m: Add pixel format quirk for pi4 2024-03-16 16:50:23 +00:00
Andri Yngvason ddf023fd3a h264-v4l2m2m: Select matching pixel format 2024-03-16 16:01:20 +00:00
Andri Yngvason 8c4c2cfa5c WiP: Implement v4l2m2m h264 encoder 2024-03-12 22:25:11 +00:00
Andri Yngvason 2bfa86a24c Create abstract h264 encoder interface 2024-03-10 16:03:36 +00:00
Andri Yngvason 2d8be463e5 Rename h264-encoder.c -> h264-encoder-ffmpeg-impl.c 2024-03-10 13:38:56 +00:00
8 changed files with 12 additions and 128 deletions

1
.gitignore vendored
View File

@ -8,4 +8,3 @@ build
experiments experiments
subprojects subprojects
sandbox sandbox
.vscode

View File

@ -1,2 +1 @@
github: any1
patreon: andriyngvason patreon: andriyngvason

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2024 Andri Yngvason * Copyright (c) 2019 - 2020 Andri Yngvason
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -109,8 +109,6 @@ struct nvnc_client {
uint32_t cursor_seq; uint32_t cursor_seq;
int quality; int quality;
bool formats_changed; bool formats_changed;
enum nvnc_keyboard_led_state led_state;
enum nvnc_keyboard_led_state pending_led_state;
#ifdef HAVE_CRYPTO #ifdef HAVE_CRYPTO
struct crypto_key* apple_dh_secret; struct crypto_key* apple_dh_secret;
@ -131,7 +129,6 @@ enum nvnc__socket_type {
NVNC__SOCKET_TCP, NVNC__SOCKET_TCP,
NVNC__SOCKET_UNIX, NVNC__SOCKET_UNIX,
NVNC__SOCKET_WEBSOCKET, NVNC__SOCKET_WEBSOCKET,
NVNC__SOCKET_FROM_FD,
}; };
struct nvnc { struct nvnc {

View File

@ -86,12 +86,6 @@ enum nvnc_transform {
NVNC_TRANSFORM_FLIPPED_270 = 7, NVNC_TRANSFORM_FLIPPED_270 = 7,
}; };
enum nvnc_keyboard_led_state {
NVNC_KEYBOARD_LED_SCROLL_LOCK = 1 << 0,
NVNC_KEYBOARD_LED_NUM_LOCK = 1 << 1,
NVNC_KEYBOARD_LED_CAPS_LOCK = 1 << 2,
};
enum nvnc_log_level { enum nvnc_log_level {
NVNC_LOG_PANIC = 0, NVNC_LOG_PANIC = 0,
NVNC_LOG_ERROR = 1, NVNC_LOG_ERROR = 1,
@ -138,7 +132,6 @@ extern const char nvnc_version[];
struct nvnc* nvnc_open(const char* addr, uint16_t port); struct nvnc* nvnc_open(const char* addr, uint16_t port);
struct nvnc* nvnc_open_unix(const char *addr); struct nvnc* nvnc_open_unix(const char *addr);
struct nvnc* nvnc_open_websocket(const char* addr, uint16_t port); struct nvnc* nvnc_open_websocket(const char* addr, uint16_t port);
struct nvnc* nvnc_open_from_fd(int fd);
void nvnc_close(struct nvnc* self); void nvnc_close(struct nvnc* self);
void nvnc_add_display(struct nvnc*, struct nvnc_display*); void nvnc_add_display(struct nvnc*, struct nvnc_display*);
@ -157,9 +150,6 @@ struct nvnc_client* nvnc_client_first(struct nvnc* self);
struct nvnc_client* nvnc_client_next(struct nvnc_client* client); struct nvnc_client* nvnc_client_next(struct nvnc_client* client);
void nvnc_client_close(struct nvnc_client* client); void nvnc_client_close(struct nvnc_client* client);
void nvnc_client_set_led_state(struct nvnc_client*,
enum nvnc_keyboard_led_state);
void nvnc_set_name(struct nvnc* self, const char* name); void nvnc_set_name(struct nvnc* self, const char* name);
void nvnc_set_key_fn(struct nvnc* self, nvnc_key_fn); void nvnc_set_key_fn(struct nvnc* self, nvnc_key_fn);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2024 Andri Yngvason * Copyright (c) 2019 - 2022 Andri Yngvason
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -69,11 +69,9 @@ enum rfb_encodings {
RFB_ENCODING_CURSOR = -239, RFB_ENCODING_CURSOR = -239,
RFB_ENCODING_DESKTOPSIZE = -223, RFB_ENCODING_DESKTOPSIZE = -223,
RFB_ENCODING_QEMU_EXT_KEY_EVENT = -258, RFB_ENCODING_QEMU_EXT_KEY_EVENT = -258,
RFB_ENCODING_QEMU_LED_STATE = -261,
RFB_ENCODING_EXTENDEDDESKTOPSIZE = -308, RFB_ENCODING_EXTENDEDDESKTOPSIZE = -308,
RFB_ENCODING_PTS = -1000, RFB_ENCODING_PTS = -1000,
RFB_ENCODING_NTP = -1001, RFB_ENCODING_NTP = -1001,
RFB_ENCODING_VMWARE_LED_STATE = 0x574d5668,
}; };
#define RFB_ENCODING_JPEG_HIGHQ -23 #define RFB_ENCODING_JPEG_HIGHQ -23
@ -116,13 +114,6 @@ enum rfb_rsa_aes_cred_subtype {
RFB_RSA_AES_CRED_SUBTYPE_ONLY_PASS = 2, RFB_RSA_AES_CRED_SUBTYPE_ONLY_PASS = 2,
}; };
// This is the same for both qemu and vmware extensions
enum rfb_led_state {
RFB_LED_STATE_SCROLL_LOCK = 1 << 0,
RFB_LED_STATE_NUM_LOCK = 1 << 1,
RFB_LED_STATE_CAPS_LOCK = 1 << 2,
};
struct rfb_security_types_msg { struct rfb_security_types_msg {
uint8_t n; uint8_t n;
uint8_t types[0]; uint8_t types[0];

View File

@ -310,11 +310,9 @@ static int h264_encoder__init_codec_context(struct h264_encoder_ffmpeg* self,
c->global_quality = quality; c->global_quality = quality;
/* open-h264 requires baseline profile, so we use constrained /* open-h264 requires baseline profile, so we use constrained
* baseline: AV_PROFILE_H264_BASELINE. * baseline.
* But that is not supported by many clients. So we use a "DEFAULT" profile.
*
*/ */
c->profile = AV_PROFILE_H264_MAIN; c->profile = 578;
return 0; return 0;
} }

View File

@ -1,19 +1,3 @@
/*
* Copyright (c) 2024 Andri Yngvason
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "h264-encoder.h" #include "h264-encoder.h"
#include "neatvnc.h" #include "neatvnc.h"
#include "fb.h" #include "fb.h"

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019 - 2024 Andri Yngvason * Copyright (c) 2019 - 2022 Andri Yngvason
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -85,7 +85,6 @@ static void process_fb_update_requests(struct nvnc_client* client);
static void sockaddr_to_string(char* dst, size_t sz, static void sockaddr_to_string(char* dst, size_t sz,
const struct sockaddr* addr); const struct sockaddr* addr);
static const char* encoding_to_string(enum rfb_encodings encoding); static const char* encoding_to_string(enum rfb_encodings encoding);
static bool client_send_led_state(struct nvnc_client* client);
#if defined(PROJECT_VERSION) #if defined(PROJECT_VERSION)
EXPORT const char nvnc_version[] = PROJECT_VERSION; EXPORT const char nvnc_version[] = PROJECT_VERSION;
@ -1026,8 +1025,6 @@ static int on_client_set_encodings(struct nvnc_client* client)
case RFB_ENCODING_DESKTOPSIZE: case RFB_ENCODING_DESKTOPSIZE:
case RFB_ENCODING_EXTENDEDDESKTOPSIZE: case RFB_ENCODING_EXTENDEDDESKTOPSIZE:
case RFB_ENCODING_QEMU_EXT_KEY_EVENT: case RFB_ENCODING_QEMU_EXT_KEY_EVENT:
case RFB_ENCODING_QEMU_LED_STATE:
case RFB_ENCODING_VMWARE_LED_STATE:
#ifdef ENABLE_EXPERIMENTAL #ifdef ENABLE_EXPERIMENTAL
case RFB_ENCODING_PTS: case RFB_ENCODING_PTS:
case RFB_ENCODING_NTP: case RFB_ENCODING_NTP:
@ -1120,8 +1117,6 @@ static const char* encoding_to_string(enum rfb_encodings encoding)
case RFB_ENCODING_DESKTOPSIZE: return "desktop-size"; case RFB_ENCODING_DESKTOPSIZE: return "desktop-size";
case RFB_ENCODING_EXTENDEDDESKTOPSIZE: return "extended-desktop-size"; case RFB_ENCODING_EXTENDEDDESKTOPSIZE: return "extended-desktop-size";
case RFB_ENCODING_QEMU_EXT_KEY_EVENT: return "qemu-extended-key-event"; case RFB_ENCODING_QEMU_EXT_KEY_EVENT: return "qemu-extended-key-event";
case RFB_ENCODING_QEMU_LED_STATE: return "qemu-led-state";
case RFB_ENCODING_VMWARE_LED_STATE: return "vmware-led-state";
case RFB_ENCODING_PTS: return "pts"; case RFB_ENCODING_PTS: return "pts";
case RFB_ENCODING_NTP: return "ntp"; case RFB_ENCODING_NTP: return "ntp";
} }
@ -1230,11 +1225,6 @@ static void process_fb_update_requests(struct nvnc_client* client)
return; return;
} }
if (client_send_led_state(client)) {
if (--client->n_pending_requests <= 0)
return;
}
if (!pixman_region_not_empty(&client->damage)) if (!pixman_region_not_empty(&client->damage))
return; return;
@ -1806,7 +1796,6 @@ static void on_connection(void* obj)
client->ref = 1; client->ref = 1;
client->server = server; client->server = server;
client->quality = 10; /* default to lossless */ client->quality = 10; /* default to lossless */
client->led_state = -1; /* trigger sending of initial state */
int fd = accept(server->fd, NULL, 0); int fd = accept(server->fd, NULL, 0);
if (fd < 0) { if (fd < 0) {
@ -1975,7 +1964,7 @@ static int bind_address_unix(const char* name)
} }
static int bind_address(const char* name, uint16_t port, static int bind_address(const char* name, uint16_t port,
int fd, enum nvnc__socket_type type) enum nvnc__socket_type type)
{ {
switch (type) { switch (type) {
case NVNC__SOCKET_TCP: case NVNC__SOCKET_TCP:
@ -1983,9 +1972,6 @@ static int bind_address(const char* name, uint16_t port,
return bind_address_tcp(name, port); return bind_address_tcp(name, port);
case NVNC__SOCKET_UNIX: case NVNC__SOCKET_UNIX:
return bind_address_unix(name); return bind_address_unix(name);
case NVNC__SOCKET_FROM_FD:
// nothing to bind
return fd;
} }
nvnc_log(NVNC_LOG_PANIC, "Unknown socket address type"); nvnc_log(NVNC_LOG_PANIC, "Unknown socket address type");
@ -1993,7 +1979,7 @@ static int bind_address(const char* name, uint16_t port,
} }
static struct nvnc* open_common(const char* address, uint16_t port, static struct nvnc* open_common(const char* address, uint16_t port,
int fd, enum nvnc__socket_type type) enum nvnc__socket_type type)
{ {
nvnc__log_init(); nvnc__log_init();
@ -2009,7 +1995,7 @@ static struct nvnc* open_common(const char* address, uint16_t port,
LIST_INIT(&self->clients); LIST_INIT(&self->clients);
self->fd = bind_address(address, port, fd, type); self->fd = bind_address(address, port, type);
if (self->fd < 0) if (self->fd < 0)
goto bind_failure; goto bind_failure;
@ -2042,14 +2028,14 @@ bind_failure:
EXPORT EXPORT
struct nvnc* nvnc_open(const char* address, uint16_t port) struct nvnc* nvnc_open(const char* address, uint16_t port)
{ {
return open_common(address, port, -1, NVNC__SOCKET_TCP); return open_common(address, port, NVNC__SOCKET_TCP);
} }
EXPORT EXPORT
struct nvnc* nvnc_open_websocket(const char *address, uint16_t port) struct nvnc* nvnc_open_websocket(const char *address, uint16_t port)
{ {
#ifdef ENABLE_WEBSOCKET #ifdef ENABLE_WEBSOCKET
return open_common(address, port, -1, NVNC__SOCKET_WEBSOCKET); return open_common(address, port, NVNC__SOCKET_WEBSOCKET);
#else #else
return NULL; return NULL;
#endif #endif
@ -2058,13 +2044,7 @@ struct nvnc* nvnc_open_websocket(const char *address, uint16_t port)
EXPORT EXPORT
struct nvnc* nvnc_open_unix(const char* address) struct nvnc* nvnc_open_unix(const char* address)
{ {
return open_common(address, 0, -1, NVNC__SOCKET_UNIX); return open_common(address, 0, NVNC__SOCKET_UNIX);
}
EXPORT
struct nvnc* nvnc_open_from_fd(int fd)
{
return open_common(NULL, 0, fd, NVNC__SOCKET_FROM_FD);
} }
static void unlink_fd_path(int fd) static void unlink_fd_path(int fd)
@ -2129,7 +2109,7 @@ static void complete_fb_update(struct nvnc_client* client)
client->current_fb = NULL; client->current_fb = NULL;
process_fb_update_requests(client); process_fb_update_requests(client);
client_unref(client); client_unref(client);
DTRACE_PROBE1(neatvnc, update_fb_done, client); DTRACE_PROBE2(neatvnc, update_fb_done, client, pts);
} }
static void on_write_frame_done(void* userdata, enum stream_req_status status) static void on_write_frame_done(void* userdata, enum stream_req_status status)
@ -2445,60 +2425,6 @@ bool nvnc_client_supports_cursor(const struct nvnc_client* client)
return false; return false;
} }
static bool client_send_led_state(struct nvnc_client* client)
{
if (client->pending_led_state == client->led_state)
return false;
bool have_qemu_led_state =
client_has_encoding(client, RFB_ENCODING_QEMU_LED_STATE);
bool have_vmware_led_state =
client_has_encoding(client, RFB_ENCODING_VMWARE_LED_STATE);
if (!have_qemu_led_state && !have_vmware_led_state)
return false;
nvnc_log(NVNC_LOG_DEBUG, "Keyboard LED state changed: %x -> %x",
client->led_state, client->pending_led_state);
struct vec payload;
vec_init(&payload, 4096);
struct rfb_server_fb_update_msg head = {
.type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
.n_rects = htons(1),
};
struct rfb_server_fb_rect rect = {
.encoding = htonl(RFB_ENCODING_QEMU_LED_STATE),
};
vec_append(&payload, &head, sizeof(head));
vec_append(&payload, &rect, sizeof(rect));
if (have_qemu_led_state) {
uint8_t data = client->pending_led_state;
vec_append(&payload, &data, sizeof(data));
} else if (have_vmware_led_state) {
uint32_t data = htonl(client->pending_led_state);
vec_append(&payload, &data, sizeof(data));
}
stream_send(client->net_stream, rcbuf_new(payload.data, payload.len),
NULL, NULL);
client->led_state = client->pending_led_state;
return true;
}
EXPORT
void nvnc_client_set_led_state(struct nvnc_client* client,
enum nvnc_keyboard_led_state state)
{
client->pending_led_state = state;
process_fb_update_requests(client);
}
EXPORT EXPORT
void nvnc_set_name(struct nvnc* self, const char* name) void nvnc_set_name(struct nvnc* self, const char* name)
{ {