Add JPEG Tight encoding
parent
8ec33ab775
commit
8cd33d8a07
3
Makefile
3
Makefile
|
@ -1,10 +1,11 @@
|
||||||
DEPENDENCIES := pixman-1 libuv
|
DEPENDENCIES := pixman-1 libuv libturbojpeg
|
||||||
|
|
||||||
SOURCES := \
|
SOURCES := \
|
||||||
src/server.c \
|
src/server.c \
|
||||||
src/util.c \
|
src/util.c \
|
||||||
src/vec.c \
|
src/vec.c \
|
||||||
src/zrle.c \
|
src/zrle.c \
|
||||||
|
src/tight.c \
|
||||||
src/raw-encoding.c \
|
src/raw-encoding.c \
|
||||||
src/pixels.c \
|
src/pixels.c \
|
||||||
src/damage.c \
|
src/damage.c \
|
||||||
|
|
|
@ -50,6 +50,7 @@ enum rfb_encodings {
|
||||||
RFB_ENCODING_COPYRECT = 1,
|
RFB_ENCODING_COPYRECT = 1,
|
||||||
RFB_ENCODING_RRE = 2,
|
RFB_ENCODING_RRE = 2,
|
||||||
RFB_ENCODING_HEXTILE = 5,
|
RFB_ENCODING_HEXTILE = 5,
|
||||||
|
RFB_ENCODING_TIGHT = 7,
|
||||||
RFB_ENCODING_TRLE = 15,
|
RFB_ENCODING_TRLE = 15,
|
||||||
RFB_ENCODING_ZRLE = 16,
|
RFB_ENCODING_ZRLE = 16,
|
||||||
RFB_ENCODING_CURSOR = -239,
|
RFB_ENCODING_CURSOR = -239,
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
struct nvnc_fb;
|
||||||
|
struct rfb_pixel_format;
|
||||||
|
struct pixman_region16;
|
||||||
|
struct vec;
|
||||||
|
|
||||||
|
int tight_encode_frame(struct vec* dst, const struct rfb_pixel_format* dst_fmt,
|
||||||
|
const struct nvnc_fb* src, uint32_t src_fmt,
|
||||||
|
struct pixman_region16* region);
|
|
@ -35,6 +35,7 @@ libm = cc.find_library('m', required: false)
|
||||||
|
|
||||||
pixman = dependency('pixman-1')
|
pixman = dependency('pixman-1')
|
||||||
libuv = dependency('libuv')
|
libuv = dependency('libuv')
|
||||||
|
libturbojpeg = dependency('libturbojpeg')
|
||||||
|
|
||||||
inc = include_directories('include', 'contrib/miniz')
|
inc = include_directories('include', 'contrib/miniz')
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ sources = [
|
||||||
'src/util.c',
|
'src/util.c',
|
||||||
'src/vec.c',
|
'src/vec.c',
|
||||||
'src/zrle.c',
|
'src/zrle.c',
|
||||||
|
'src/tight.c',
|
||||||
'src/raw-encoding.c',
|
'src/raw-encoding.c',
|
||||||
'src/pixels.c',
|
'src/pixels.c',
|
||||||
'src/damage.c',
|
'src/damage.c',
|
||||||
|
@ -54,6 +56,7 @@ dependencies = [
|
||||||
libm,
|
libm,
|
||||||
pixman,
|
pixman,
|
||||||
libuv,
|
libuv,
|
||||||
|
libturbojpeg,
|
||||||
]
|
]
|
||||||
|
|
||||||
neatvnc = shared_library(
|
neatvnc = shared_library(
|
||||||
|
|
11
src/server.c
11
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 "tight.h"
|
||||||
#include "raw-encoding.h"
|
#include "raw-encoding.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
#include "type-macros.h"
|
#include "type-macros.h"
|
||||||
|
@ -539,6 +540,7 @@ static int on_client_set_encodings(struct nvnc_client* client)
|
||||||
case RFB_ENCODING_COPYRECT:
|
case RFB_ENCODING_COPYRECT:
|
||||||
case RFB_ENCODING_RRE:
|
case RFB_ENCODING_RRE:
|
||||||
case RFB_ENCODING_HEXTILE:
|
case RFB_ENCODING_HEXTILE:
|
||||||
|
case RFB_ENCODING_TIGHT:
|
||||||
case RFB_ENCODING_TRLE:
|
case RFB_ENCODING_TRLE:
|
||||||
case RFB_ENCODING_ZRLE:
|
case RFB_ENCODING_ZRLE:
|
||||||
case RFB_ENCODING_CURSOR:
|
case RFB_ENCODING_CURSOR:
|
||||||
|
@ -883,6 +885,9 @@ enum rfb_encodings choose_frame_encoding(struct nvnc_client* client)
|
||||||
for (int i = 0; i < client->n_encodings; ++i)
|
for (int i = 0; i < client->n_encodings; ++i)
|
||||||
switch (client->encodings[i]) {
|
switch (client->encodings[i]) {
|
||||||
case RFB_ENCODING_RAW:
|
case RFB_ENCODING_RAW:
|
||||||
|
#ifdef ENABLE_TIGHT
|
||||||
|
case RFB_ENCODING_TIGHT:
|
||||||
|
#endif
|
||||||
case RFB_ENCODING_ZRLE:
|
case RFB_ENCODING_ZRLE:
|
||||||
return client->encodings[i];
|
return client->encodings[i];
|
||||||
default:
|
default:
|
||||||
|
@ -906,6 +911,12 @@ void do_client_update_fb(uv_work_t* work)
|
||||||
raw_encode_frame(&update->frame, &client->pixfmt, fb,
|
raw_encode_frame(&update->frame, &client->pixfmt, fb,
|
||||||
&update->server_fmt, &update->region);
|
&update->server_fmt, &update->region);
|
||||||
break;
|
break;
|
||||||
|
#ifdef ENABLE_TIGHT
|
||||||
|
case RFB_ENCODING_TIGHT:
|
||||||
|
tight_encode_frame(&update->frame, &client->pixfmt, fb,
|
||||||
|
fb->fourcc_format, &update->region);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case RFB_ENCODING_ZRLE:
|
case RFB_ENCODING_ZRLE:
|
||||||
zrle_encode_frame(&client->z_stream, &update->frame,
|
zrle_encode_frame(&client->z_stream, &update->frame,
|
||||||
&client->pixfmt, fb, &update->server_fmt,
|
&client->pixfmt, fb, &update->server_fmt,
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
#include "neatvnc.h"
|
||||||
|
#include "rfb-proto.h"
|
||||||
|
#include "vec.h"
|
||||||
|
#include "fb.h"
|
||||||
|
|
||||||
|
#include <pixman.h>
|
||||||
|
#include <turbojpeg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <libdrm/drm_fourcc.h>
|
||||||
|
|
||||||
|
#define TIGHT_FILL 0x80
|
||||||
|
#define TIGHT_JPEG 0x90
|
||||||
|
#define TIGHT_PNG 0xA0
|
||||||
|
#define TIGHT_BASIC 0x00
|
||||||
|
|
||||||
|
enum TJPF get_jpeg_pixfmt(uint32_t fourcc)
|
||||||
|
{
|
||||||
|
switch (fourcc) {
|
||||||
|
case DRM_FORMAT_RGBA8888:
|
||||||
|
case DRM_FORMAT_RGBX8888:
|
||||||
|
return TJPF_XRGB;
|
||||||
|
case DRM_FORMAT_BGRA8888:
|
||||||
|
case DRM_FORMAT_BGRX8888:
|
||||||
|
return TJPF_XBGR;
|
||||||
|
case DRM_FORMAT_ARGB8888:
|
||||||
|
case DRM_FORMAT_XRGB8888:
|
||||||
|
return TJPF_RGBX;
|
||||||
|
case DRM_FORMAT_ABGR8888:
|
||||||
|
case DRM_FORMAT_XBGR8888:
|
||||||
|
return TJPF_BGRX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TJPF_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tight_encode_size(struct vec* dst, size_t size)
|
||||||
|
{
|
||||||
|
vec_fast_append_8(dst, (size & 0x7f) | ((size >= 128) << 7));
|
||||||
|
if (size >= 128)
|
||||||
|
vec_fast_append_8(dst, ((size >> 7) & 0x7f) | ((size >= 16384) << 7));
|
||||||
|
if (size >= 16384)
|
||||||
|
vec_fast_append_8(dst, (size >> 14) & 0x7f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tight_encode_box(struct vec* dst, const struct rfb_pixel_format* dst_fmt,
|
||||||
|
const struct nvnc_fb* src, uint32_t src_fmt,
|
||||||
|
uint32_t x, uint32_t y, uint32_t stride,
|
||||||
|
uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned char* buffer = NULL;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
int quality = 50; /* 1 - 100 */
|
||||||
|
enum TJPF tjfmt = get_jpeg_pixfmt(src_fmt);
|
||||||
|
if (tjfmt == TJPF_UNKNOWN)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
vec_reserve(dst, 4096);
|
||||||
|
|
||||||
|
struct rfb_server_fb_rect rect = {
|
||||||
|
.encoding = htonl(RFB_ENCODING_TIGHT),
|
||||||
|
.x = htons(x),
|
||||||
|
.y = htons(y),
|
||||||
|
.width = htons(width),
|
||||||
|
.height = htons(height),
|
||||||
|
};
|
||||||
|
|
||||||
|
vec_append(dst, &rect, sizeof(rect));
|
||||||
|
|
||||||
|
tjhandle handle = tjInitCompress();
|
||||||
|
|
||||||
|
void* img = (uint32_t*)src->addr + x + y * stride;
|
||||||
|
|
||||||
|
tjCompress2(handle, img, width, stride * 4, height, tjfmt, &buffer,
|
||||||
|
&size, TJSAMP_422, quality, TJFLAG_FASTDCT);
|
||||||
|
|
||||||
|
vec_fast_append_8(dst, TIGHT_JPEG);
|
||||||
|
|
||||||
|
tight_encode_size(dst, size);
|
||||||
|
|
||||||
|
vec_append(dst, buffer, size);
|
||||||
|
|
||||||
|
tjFree(buffer);
|
||||||
|
tjDestroy(handle);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tight_encode_frame(struct vec* dst, const struct rfb_pixel_format* dst_fmt,
|
||||||
|
const struct nvnc_fb* src, uint32_t 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 = tight_encode_box(dst, dst_fmt, src, src_fmt, x, y,
|
||||||
|
src->width, box_width, box_height);
|
||||||
|
if (rc < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue