parent
7b57449e19
commit
40f16fe63b
1
Makefile
1
Makefile
|
@ -5,6 +5,7 @@ SOURCES := \
|
||||||
src/util.c \
|
src/util.c \
|
||||||
src/vec.c \
|
src/vec.c \
|
||||||
src/zrle.c \
|
src/zrle.c \
|
||||||
|
src/raw-encoding.c \
|
||||||
src/pixels.c \
|
src/pixels.c \
|
||||||
src/damage.c \
|
src/damage.c \
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct nvnc_fb;
|
||||||
|
struct rfb_pixel_format;
|
||||||
|
struct pixman_region16;
|
||||||
|
struct vec;
|
||||||
|
|
||||||
|
int raw_encode_frame(struct vec *dst,
|
||||||
|
const struct rfb_pixel_format *dst_fmt,
|
||||||
|
const struct nvnc_fb *src,
|
||||||
|
const struct rfb_pixel_format *src_fmt,
|
||||||
|
struct pixman_region16 *region);
|
|
@ -52,7 +52,8 @@ static inline void vec_fast_append_32(struct vec* vec, uint32_t value)
|
||||||
{
|
{
|
||||||
assert(vec->len + sizeof(value) <= vec->cap);
|
assert(vec->len + sizeof(value) <= vec->cap);
|
||||||
assert(vec->len % sizeof(value) == 0);
|
assert(vec->len % sizeof(value) == 0);
|
||||||
((uint32_t*)vec->data)[vec->len] = value;
|
uint32_t* p = (uint32_t*)((uint8_t*)vec->data + vec->len);
|
||||||
|
*p = value;
|
||||||
vec->len += sizeof(value);
|
vec->len += sizeof(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
#include "neatvnc.h"
|
||||||
|
#include "rfb-proto.h"
|
||||||
|
#include "vec.h"
|
||||||
|
|
||||||
|
#include <pixman.h>
|
||||||
|
|
||||||
|
int raw_encode_box(struct vec *dst, const struct rfb_pixel_format *dst_fmt,
|
||||||
|
const struct nvnc_fb *fb,
|
||||||
|
const struct rfb_pixel_format *src_fmt,
|
||||||
|
int x_start, int y_start, int stride, int width, int height)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
|
||||||
|
struct rfb_server_fb_rect rect = {
|
||||||
|
.encoding = htonl(RFB_ENCODING_RAW),
|
||||||
|
.x = htons(x_start),
|
||||||
|
.y = htons(y_start),
|
||||||
|
.width = htons(width),
|
||||||
|
.height = htons(height),
|
||||||
|
};
|
||||||
|
|
||||||
|
rc = vec_reserve(dst, width * height * 4 + 256);
|
||||||
|
if (rc < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rc = vec_append(dst, &rect, sizeof(rect));
|
||||||
|
if (rc < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
uint32_t* b = fb->addr;
|
||||||
|
|
||||||
|
if (fb->nvnc_modifier & NVNC_MOD_Y_INVERT)
|
||||||
|
y_start = fb->height - y_start - height;
|
||||||
|
|
||||||
|
/* TODO: Pixel format conversion */
|
||||||
|
for (int y = y_start; y < y_start + height; ++y)
|
||||||
|
for (int x = x_start; x < x_start + width; ++x)
|
||||||
|
vec_fast_append_32(dst, b[x + y * stride]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int raw_encode_frame(struct vec *dst,
|
||||||
|
const struct rfb_pixel_format *dst_fmt,
|
||||||
|
const struct nvnc_fb *src,
|
||||||
|
const struct rfb_pixel_format *src_fmt,
|
||||||
|
struct pixman_region16 *region)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
|
||||||
|
int n_rects = 0;
|
||||||
|
struct pixman_box16 *box = pixman_region_rectangles(region, &n_rects);
|
||||||
|
if (n_rects > UINT16_MAX) {
|
||||||
|
box = pixman_region_extents(region);
|
||||||
|
n_rects = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rfb_server_fb_update_msg head = {
|
||||||
|
.type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
|
||||||
|
.n_rects = htons(n_rects),
|
||||||
|
};
|
||||||
|
|
||||||
|
rc = vec_append(dst, &head, sizeof(head));
|
||||||
|
if (rc < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < n_rects; ++i) {
|
||||||
|
int x = box[i].x1;
|
||||||
|
int y = box[i].y1;
|
||||||
|
int box_width = box[i].x2 - x;
|
||||||
|
int box_height = box[i].y2 - y;
|
||||||
|
|
||||||
|
rc = raw_encode_box(dst, dst_fmt, src, src_fmt, x, y,
|
||||||
|
src->width, box_width, box_height);
|
||||||
|
if (rc < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
73
src/server.c
73
src/server.c
|
@ -17,6 +17,7 @@
|
||||||
#include "rfb-proto.h"
|
#include "rfb-proto.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "zrle.h"
|
#include "zrle.h"
|
||||||
|
#include "raw-encoding.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
#include "type-macros.h"
|
#include "type-macros.h"
|
||||||
#include "neatvnc.h"
|
#include "neatvnc.h"
|
||||||
|
@ -42,18 +43,9 @@
|
||||||
#define READ_BUFFER_SIZE 4096
|
#define READ_BUFFER_SIZE 4096
|
||||||
#define MSG_BUFFER_SIZE 4096
|
#define MSG_BUFFER_SIZE 4096
|
||||||
|
|
||||||
#define EXPORT __attribute__((visibility("default")))
|
#define MAX_ENCODINGS 32
|
||||||
|
|
||||||
enum vnc_encodings {
|
#define EXPORT __attribute__((visibility("default")))
|
||||||
VNC_ENCODING_RAW = 1 << 0,
|
|
||||||
VNC_ENCODING_COPYRECT = 1 << 1,
|
|
||||||
VNC_ENCODING_RRE = 1 << 2,
|
|
||||||
VNC_ENCODING_HEXTILE = 1 << 3,
|
|
||||||
VNC_ENCODING_TRLE = 1 << 4,
|
|
||||||
VNC_ENCODING_ZRLE = 1 << 5,
|
|
||||||
VNC_ENCODING_CURSOR = 1 << 6,
|
|
||||||
VNC_ENCODING_DESKTOPSIZE = 1 << 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum nvnc_client_state {
|
enum nvnc_client_state {
|
||||||
VNC_CLIENT_STATE_ERROR = -1,
|
VNC_CLIENT_STATE_ERROR = -1,
|
||||||
|
@ -77,7 +69,8 @@ struct nvnc_client {
|
||||||
enum nvnc_client_state state;
|
enum nvnc_client_state state;
|
||||||
uint32_t fourcc;
|
uint32_t fourcc;
|
||||||
struct rfb_pixel_format pixfmt;
|
struct rfb_pixel_format pixfmt;
|
||||||
enum vnc_encodings encodings;
|
enum rfb_encodings encodings[MAX_ENCODINGS + 1];
|
||||||
|
size_t n_encodings;
|
||||||
LIST_ENTRY(nvnc_client) link;
|
LIST_ENTRY(nvnc_client) link;
|
||||||
struct pixman_region16 requested_region;
|
struct pixman_region16 requested_region;
|
||||||
nvnc_client_fn cleanup_fn;
|
nvnc_client_fn cleanup_fn;
|
||||||
|
@ -524,23 +517,23 @@ static int on_client_set_encodings(struct nvnc_client *client)
|
||||||
(struct rfb_client_set_encodings_msg*)(client->msg_buffer +
|
(struct rfb_client_set_encodings_msg*)(client->msg_buffer +
|
||||||
client->buffer_index);
|
client->buffer_index);
|
||||||
|
|
||||||
int n_encodings = ntohs(msg->n_encodings);
|
int n_encodings = MIN(MAX_ENCODINGS, ntohs(msg->n_encodings));
|
||||||
|
int n = 0;
|
||||||
uint32_t e = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < n_encodings; ++i)
|
for (int i = 0; i < n_encodings; ++i)
|
||||||
switch (msg->encodings[i]) {
|
switch (msg->encodings[i]) {
|
||||||
case RFB_ENCODING_RAW: e |= VNC_ENCODING_RAW;
|
case RFB_ENCODING_RAW:
|
||||||
case RFB_ENCODING_COPYRECT: e |= VNC_ENCODING_COPYRECT;
|
case RFB_ENCODING_COPYRECT:
|
||||||
case RFB_ENCODING_RRE: e |= VNC_ENCODING_RRE;
|
case RFB_ENCODING_RRE:
|
||||||
case RFB_ENCODING_HEXTILE: e |= VNC_ENCODING_HEXTILE;
|
case RFB_ENCODING_HEXTILE:
|
||||||
case RFB_ENCODING_TRLE: e |= VNC_ENCODING_TRLE;
|
case RFB_ENCODING_TRLE:
|
||||||
case RFB_ENCODING_ZRLE: e |= VNC_ENCODING_ZRLE;
|
case RFB_ENCODING_ZRLE:
|
||||||
case RFB_ENCODING_CURSOR: e |= VNC_ENCODING_CURSOR;
|
case RFB_ENCODING_CURSOR:
|
||||||
case RFB_ENCODING_DESKTOPSIZE: e |= VNC_ENCODING_COPYRECT;
|
case RFB_ENCODING_DESKTOPSIZE:
|
||||||
|
client->encodings[n++] = msg->encodings[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
client->encodings = e;
|
client->n_encodings = n;
|
||||||
|
|
||||||
return sizeof(*msg) + 4 * n_encodings;
|
return sizeof(*msg) + 4 * n_encodings;
|
||||||
}
|
}
|
||||||
|
@ -817,14 +810,42 @@ static void free_write_buffer(uv_write_t *req, int status)
|
||||||
free(rq->buffer.base);
|
free(rq->buffer.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum rfb_encodings choose_frame_encoding(struct nvnc_client *client)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < client->n_encodings; ++i)
|
||||||
|
switch (client->encodings[i]) {
|
||||||
|
case RFB_ENCODING_RAW:
|
||||||
|
case RFB_ENCODING_ZRLE:
|
||||||
|
return client->encodings[i];
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void do_client_update_fb(uv_work_t *work)
|
void do_client_update_fb(uv_work_t *work)
|
||||||
{
|
{
|
||||||
struct fb_update_work *update = (void*)work;
|
struct fb_update_work *update = (void*)work;
|
||||||
struct nvnc_client *client = update->client;
|
struct nvnc_client *client = update->client;
|
||||||
const struct nvnc_fb *fb = update->fb;
|
const struct nvnc_fb *fb = update->fb;
|
||||||
|
|
||||||
zrle_encode_frame(&client->z_stream, &update->frame, &client->pixfmt,
|
enum rfb_encodings encoding = choose_frame_encoding(client);
|
||||||
fb, &update->server_fmt, &update->region);
|
assert(encoding != -1);
|
||||||
|
|
||||||
|
switch (encoding) {
|
||||||
|
case RFB_ENCODING_RAW:
|
||||||
|
raw_encode_frame(&update->frame, &client->pixfmt, fb,
|
||||||
|
&update->server_fmt, &update->region);
|
||||||
|
break;
|
||||||
|
case RFB_ENCODING_ZRLE:
|
||||||
|
zrle_encode_frame(&client->z_stream, &update->frame,
|
||||||
|
&client->pixfmt, fb, &update->server_fmt,
|
||||||
|
&update->region);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_client_update_fb_done(uv_work_t *work, int status)
|
void on_client_update_fb_done(uv_work_t *work, int status)
|
||||||
|
|
Loading…
Reference in New Issue