tight: Implement bare minimum "basic" encoding
parent
cfb2abfc58
commit
17e0d6036f
|
@ -22,6 +22,7 @@ struct vec;
|
||||||
struct nvnc_client;
|
struct nvnc_client;
|
||||||
struct nvnc_fb;
|
struct nvnc_fb;
|
||||||
struct pixman_region16;
|
struct pixman_region16;
|
||||||
|
struct rfb_pixel_format;
|
||||||
|
|
||||||
struct tight_encoder {
|
struct tight_encoder {
|
||||||
z_stream zs[4];
|
z_stream zs[4];
|
||||||
|
@ -32,4 +33,5 @@ void tight_encoder_destroy(struct tight_encoder*);
|
||||||
|
|
||||||
int tight_encode_frame(struct tight_encoder* self, struct vec* dst,
|
int tight_encode_frame(struct tight_encoder* self, struct vec* dst,
|
||||||
const struct nvnc_fb* fb,
|
const struct nvnc_fb* fb,
|
||||||
|
const struct rfb_pixel_format* src_fmt,
|
||||||
struct pixman_region16* region);
|
struct pixman_region16* region);
|
||||||
|
|
10
src/server.c
10
src/server.c
|
@ -77,7 +77,9 @@ static void client_close(struct nvnc_client* client)
|
||||||
|
|
||||||
LIST_REMOVE(client, link);
|
LIST_REMOVE(client, link);
|
||||||
stream_destroy(client->net_stream);
|
stream_destroy(client->net_stream);
|
||||||
|
#ifdef ENABLE_TIGHT
|
||||||
tight_encoder_destroy(&client->tight_encoder);
|
tight_encoder_destroy(&client->tight_encoder);
|
||||||
|
#endif
|
||||||
deflateEnd(&client->z_stream);
|
deflateEnd(&client->z_stream);
|
||||||
pixman_region_fini(&client->damage);
|
pixman_region_fini(&client->damage);
|
||||||
free(client);
|
free(client);
|
||||||
|
@ -709,8 +711,10 @@ static void on_connection(void* obj)
|
||||||
if (rc != Z_OK)
|
if (rc != Z_OK)
|
||||||
goto deflate_failure;
|
goto deflate_failure;
|
||||||
|
|
||||||
|
#ifdef ENABLE_TIGHT
|
||||||
if (tight_encoder_init(&client->tight_encoder) < 0)
|
if (tight_encoder_init(&client->tight_encoder) < 0)
|
||||||
goto tight_failure;
|
goto tight_failure;
|
||||||
|
#endif
|
||||||
|
|
||||||
pixman_region_init(&client->damage);
|
pixman_region_init(&client->damage);
|
||||||
|
|
||||||
|
@ -729,9 +733,13 @@ static void on_connection(void* obj)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
payload_failure:
|
payload_failure:
|
||||||
|
#ifdef ENABLE_TIGHT
|
||||||
tight_encoder_destroy(&client->tight_encoder);
|
tight_encoder_destroy(&client->tight_encoder);
|
||||||
|
#endif
|
||||||
pixman_region_fini(&client->damage);
|
pixman_region_fini(&client->damage);
|
||||||
|
#ifdef ENABLE_TIGHT
|
||||||
tight_failure:
|
tight_failure:
|
||||||
|
#endif
|
||||||
deflateEnd(&client->z_stream);
|
deflateEnd(&client->z_stream);
|
||||||
deflate_failure:
|
deflate_failure:
|
||||||
stream_destroy(client->net_stream);
|
stream_destroy(client->net_stream);
|
||||||
|
@ -867,7 +875,7 @@ void do_client_update_fb(void* work)
|
||||||
#ifdef ENABLE_TIGHT
|
#ifdef ENABLE_TIGHT
|
||||||
case RFB_ENCODING_TIGHT:
|
case RFB_ENCODING_TIGHT:
|
||||||
tight_encode_frame(&client->tight_encoder, &update->frame, fb,
|
tight_encode_frame(&client->tight_encoder, &update->frame, fb,
|
||||||
&update->region);
|
&update->server_fmt, &update->region);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case RFB_ENCODING_ZRLE:
|
case RFB_ENCODING_ZRLE:
|
||||||
|
|
133
src/tight.c
133
src/tight.c
|
@ -14,13 +14,16 @@
|
||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "miniz.h"
|
||||||
#include "neatvnc.h"
|
#include "neatvnc.h"
|
||||||
#include "rfb-proto.h"
|
#include "rfb-proto.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
#include "fb.h"
|
#include "fb.h"
|
||||||
#include "tight.h"
|
#include "tight.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "pixels.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
#include "type-macros.h"
|
||||||
|
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
#include <turbojpeg.h>
|
#include <turbojpeg.h>
|
||||||
|
@ -35,15 +38,32 @@
|
||||||
|
|
||||||
#define TIGHT_MAX_WIDTH 2048
|
#define TIGHT_MAX_WIDTH 2048
|
||||||
|
|
||||||
|
int tight_init_zstream(z_stream* zx)
|
||||||
|
{
|
||||||
|
int rc = deflateInit2(zx,
|
||||||
|
/* compression level: */ 1,
|
||||||
|
/* method: */ Z_DEFLATED,
|
||||||
|
/* window bits: */ 15,
|
||||||
|
/* mem level: */ 9,
|
||||||
|
/* strategy: */ Z_DEFAULT_STRATEGY);
|
||||||
|
return rc == Z_OK ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
int tight_encoder_init(struct tight_encoder* self)
|
int tight_encoder_init(struct tight_encoder* self)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO: Implement more stream channels
|
||||||
return 0;
|
return tight_init_zstream(&self->zs[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tight_encoder_destroy(struct tight_encoder* self)
|
void tight_encoder_destroy(struct tight_encoder* self)
|
||||||
{
|
{
|
||||||
// TODO
|
deflateEnd(&self->zs[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int calc_bytes_per_cpixel(const struct rfb_pixel_format* fmt)
|
||||||
|
{
|
||||||
|
return fmt->bits_per_pixel == 32 ? fmt->depth / 8
|
||||||
|
: fmt->bits_per_pixel / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TJPF get_jpeg_pixfmt(uint32_t fourcc)
|
enum TJPF get_jpeg_pixfmt(uint32_t fourcc)
|
||||||
|
@ -128,15 +148,114 @@ compress_failure:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tight_deflate(struct vec* dst, const void* src, size_t len, z_stream* zs, bool flush)
|
||||||
|
{
|
||||||
|
int r = Z_STREAM_ERROR;
|
||||||
|
|
||||||
|
zs->next_in = src;
|
||||||
|
zs->avail_in = len;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (dst->len == dst->cap && vec_reserve(dst, dst->cap * 2) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
zs->next_out = ((Bytef*)dst->data) + dst->len;
|
||||||
|
zs->avail_out = dst->cap - dst->len;
|
||||||
|
|
||||||
|
r = deflate(zs, flush ? Z_SYNC_FLUSH : Z_NO_FLUSH);
|
||||||
|
assert(r != Z_STREAM_ERROR);
|
||||||
|
|
||||||
|
dst->len = zs->next_out - (Bytef*)dst->data;
|
||||||
|
} while (zs->avail_out == 0);
|
||||||
|
|
||||||
|
assert(zs->avail_in == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tight_encode_box_basic(struct tight_encoder* self, struct vec* dst,
|
||||||
|
const struct nvnc_fb* fb,
|
||||||
|
const struct rfb_pixel_format* src_fmt,
|
||||||
|
uint32_t x, uint32_t y_start,
|
||||||
|
uint32_t stride, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
printf("Encode %u %u %u %u\n", x, y_start, width, height);
|
||||||
|
struct nvnc_client* client =
|
||||||
|
container_of(self, struct nvnc_client, tight_encoder);
|
||||||
|
|
||||||
|
vec_reserve(dst, 4096);
|
||||||
|
|
||||||
|
int bytes_per_cpixel = calc_bytes_per_cpixel(&client->pixfmt);
|
||||||
|
uint8_t* row = malloc(bytes_per_cpixel * width);
|
||||||
|
if (!row)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
struct vec buffer;
|
||||||
|
if (vec_init(&buffer, 4096) < 0)
|
||||||
|
goto buffer_failure;
|
||||||
|
|
||||||
|
struct rfb_server_fb_rect rect = {
|
||||||
|
.encoding = htonl(RFB_ENCODING_TIGHT),
|
||||||
|
.x = htons(x),
|
||||||
|
.y = htons(y_start),
|
||||||
|
.width = htons(width),
|
||||||
|
.height = htons(height),
|
||||||
|
};
|
||||||
|
|
||||||
|
vec_append(dst, &rect, sizeof(rect));
|
||||||
|
|
||||||
|
vec_fast_append_8(dst, TIGHT_BASIC);
|
||||||
|
|
||||||
|
struct rfb_pixel_format cfmt = { 0 };
|
||||||
|
if (bytes_per_cpixel == 3)
|
||||||
|
rfb_pixfmt_from_fourcc(&cfmt, DRM_FORMAT_RGBX8888 | DRM_FORMAT_BIG_ENDIAN);
|
||||||
|
else
|
||||||
|
memcpy(&cfmt, &client->pixfmt, sizeof(cfmt));
|
||||||
|
|
||||||
|
if (width * height * bytes_per_cpixel < 12) {
|
||||||
|
for (uint32_t y = y_start; y < y_start + height; ++y) {
|
||||||
|
void* img = (uint32_t*)fb->addr + x + y * stride;
|
||||||
|
pixel32_to_cpixel(row, &cfmt, img, src_fmt,
|
||||||
|
bytes_per_cpixel, width);
|
||||||
|
vec_append(&buffer, row, width * bytes_per_cpixel);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (uint32_t y = y_start; y < y_start + height; ++y) {
|
||||||
|
void* img = (uint32_t*)fb->addr + x + y * stride;
|
||||||
|
pixel32_to_cpixel(row, &cfmt, img, src_fmt,
|
||||||
|
bytes_per_cpixel, width);
|
||||||
|
tight_deflate(&buffer, row, bytes_per_cpixel * width,
|
||||||
|
&self->zs[0], y == y_start + height - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
tight_encode_size(dst, buffer.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec_append(dst, buffer.data, buffer.len);
|
||||||
|
|
||||||
|
vec_destroy(&buffer);
|
||||||
|
free(row);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
buffer_failure:
|
||||||
|
free(row);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int tight_encode_box(struct tight_encoder* self, struct vec* dst,
|
int tight_encode_box(struct tight_encoder* self, struct vec* dst,
|
||||||
const struct nvnc_fb* fb, uint32_t x, uint32_t y,
|
const struct nvnc_fb* fb,
|
||||||
|
const struct rfb_pixel_format* src_fmt,
|
||||||
|
uint32_t x, uint32_t y,
|
||||||
uint32_t stride, uint32_t width, uint32_t height)
|
uint32_t stride, uint32_t width, uint32_t height)
|
||||||
{
|
{
|
||||||
|
// return tight_encode_box_basic(self, dst, fb, src_fmt, x, y, stride, width, height);
|
||||||
return tight_encode_box_jpeg(self, dst, fb, x, y, stride, width, height);
|
return tight_encode_box_jpeg(self, dst, fb, x, y, stride, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
int tight_encode_frame(struct tight_encoder* self, struct vec* dst,
|
int tight_encode_frame(struct tight_encoder* self, struct vec* dst,
|
||||||
const struct nvnc_fb* fb, struct pixman_region16* region)
|
const struct nvnc_fb* fb,
|
||||||
|
const struct rfb_pixel_format* src_fmt,
|
||||||
|
struct pixman_region16* region)
|
||||||
{
|
{
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
|
@ -166,8 +285,8 @@ int tight_encode_frame(struct tight_encoder* self, struct vec* dst,
|
||||||
int w = MIN(TIGHT_MAX_WIDTH, box_width);
|
int w = MIN(TIGHT_MAX_WIDTH, box_width);
|
||||||
box_width -= w;
|
box_width -= w;
|
||||||
|
|
||||||
rc = tight_encode_box(self, dst, fb, x, y, fb->width,
|
rc = tight_encode_box(self, dst, fb, src_fmt, x, y,
|
||||||
w, box_height);
|
fb->width, w, box_height);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue