Add raw encoding

It's useful for debugging
tight-png
Andri Yngvason 2019-09-19 18:14:24 +00:00
parent 7b57449e19
commit 40f16fe63b
5 changed files with 142 additions and 27 deletions

View File

@ -5,6 +5,7 @@ SOURCES := \
src/util.c \
src/vec.c \
src/zrle.c \
src/raw-encoding.c \
src/pixels.c \
src/damage.c \

View File

@ -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);

View File

@ -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) == 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);
}

80
src/raw-encoding.c 100644
View File

@ -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;
}

View File

@ -17,6 +17,7 @@
#include "rfb-proto.h"
#include "util.h"
#include "zrle.h"
#include "raw-encoding.h"
#include "vec.h"
#include "type-macros.h"
#include "neatvnc.h"
@ -42,18 +43,9 @@
#define READ_BUFFER_SIZE 4096
#define MSG_BUFFER_SIZE 4096
#define EXPORT __attribute__((visibility("default")))
#define MAX_ENCODINGS 32
enum vnc_encodings {
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,
};
#define EXPORT __attribute__((visibility("default")))
enum nvnc_client_state {
VNC_CLIENT_STATE_ERROR = -1,
@ -77,7 +69,8 @@ struct nvnc_client {
enum nvnc_client_state state;
uint32_t fourcc;
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;
struct pixman_region16 requested_region;
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 +
client->buffer_index);
int n_encodings = ntohs(msg->n_encodings);
uint32_t e = 0;
int n_encodings = MIN(MAX_ENCODINGS, ntohs(msg->n_encodings));
int n = 0;
for (int i = 0; i < n_encodings; ++i)
switch (msg->encodings[i]) {
case RFB_ENCODING_RAW: e |= VNC_ENCODING_RAW;
case RFB_ENCODING_COPYRECT: e |= VNC_ENCODING_COPYRECT;
case RFB_ENCODING_RRE: e |= VNC_ENCODING_RRE;
case RFB_ENCODING_HEXTILE: e |= VNC_ENCODING_HEXTILE;
case RFB_ENCODING_TRLE: e |= VNC_ENCODING_TRLE;
case RFB_ENCODING_ZRLE: e |= VNC_ENCODING_ZRLE;
case RFB_ENCODING_CURSOR: e |= VNC_ENCODING_CURSOR;
case RFB_ENCODING_DESKTOPSIZE: e |= VNC_ENCODING_COPYRECT;
case RFB_ENCODING_RAW:
case RFB_ENCODING_COPYRECT:
case RFB_ENCODING_RRE:
case RFB_ENCODING_HEXTILE:
case RFB_ENCODING_TRLE:
case RFB_ENCODING_ZRLE:
case RFB_ENCODING_CURSOR:
case RFB_ENCODING_DESKTOPSIZE:
client->encodings[n++] = msg->encodings[i];
}
client->encodings = e;
client->n_encodings = n;
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);
}
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)
{
struct fb_update_work *update = (void*)work;
struct nvnc_client *client = update->client;
const struct nvnc_fb *fb = update->fb;
zrle_encode_frame(&client->z_stream, &update->frame, &client->pixfmt,
fb, &update->server_fmt, &update->region);
enum rfb_encodings encoding = choose_frame_encoding(client);
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)