Try serving a png
parent
24f0c4a0d4
commit
09dfb874b1
|
@ -0,0 +1,84 @@
|
|||
#include "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <png.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
int read_png_file(struct vnc_framebuffer* fb, const char *filename) {
|
||||
int width, height;
|
||||
png_byte color_type;
|
||||
png_byte bit_depth;
|
||||
png_bytep *row_pointers = NULL;
|
||||
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
|
||||
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if(!png) abort();
|
||||
|
||||
png_infop info = png_create_info_struct(png);
|
||||
if(!info) abort();
|
||||
|
||||
if(setjmp(png_jmpbuf(png))) abort();
|
||||
|
||||
png_init_io(png, fp);
|
||||
|
||||
png_read_info(png, info);
|
||||
|
||||
width = png_get_image_width(png, info);
|
||||
height = png_get_image_height(png, info);
|
||||
color_type = png_get_color_type(png, info);
|
||||
bit_depth = png_get_bit_depth(png, info);
|
||||
|
||||
// Read any color_type into 8bit depth, RGBA format.
|
||||
// See http://www.libpng.org/pub/png/libpng-manual.txt
|
||||
|
||||
if(bit_depth == 16)
|
||||
png_set_strip_16(png);
|
||||
|
||||
if(color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_palette_to_rgb(png);
|
||||
|
||||
// PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
|
||||
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||
png_set_expand_gray_1_2_4_to_8(png);
|
||||
|
||||
if(png_get_valid(png, info, PNG_INFO_tRNS))
|
||||
png_set_tRNS_to_alpha(png);
|
||||
|
||||
// These color_type don't have an alpha channel then fill it with 0xff.
|
||||
if(color_type == PNG_COLOR_TYPE_RGB ||
|
||||
color_type == PNG_COLOR_TYPE_GRAY ||
|
||||
color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
|
||||
|
||||
if(color_type == PNG_COLOR_TYPE_GRAY ||
|
||||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
png_set_gray_to_rgb(png);
|
||||
|
||||
png_read_update_info(png, info);
|
||||
|
||||
size_t row_bytes = png_get_rowbytes(png, info);
|
||||
uint8_t *addr = malloc(row_bytes * height);
|
||||
assert(addr);
|
||||
|
||||
row_pointers = malloc(sizeof(png_bytep) * height);
|
||||
assert(row_pointers);
|
||||
|
||||
for (int y = 0; y < height; ++y)
|
||||
row_pointers[y] = addr + y * row_bytes;
|
||||
|
||||
png_read_image(png, row_pointers);
|
||||
|
||||
free(row_pointers);
|
||||
fclose(fp);
|
||||
|
||||
png_destroy_read_struct(&png, &info, NULL);
|
||||
|
||||
fb->addr = addr;
|
||||
fb->width = width;
|
||||
fb->height = height;
|
||||
|
||||
return 0;
|
||||
}
|
82
server.c
82
server.c
|
@ -1,5 +1,6 @@
|
|||
#include "rfb-proto.h"
|
||||
#include "util.h"
|
||||
#include "zrle.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
@ -7,6 +8,7 @@
|
|||
#include <assert.h>
|
||||
#include <uv.h>
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
#include <pixman.h>
|
||||
|
||||
#define READ_BUFFER_SIZE 4096
|
||||
#define MSG_BUFFER_SIZE 4096
|
||||
|
@ -36,7 +38,8 @@ struct vnc_client {
|
|||
uv_tcp_t stream_handle;
|
||||
struct vnc_server *server;
|
||||
enum vnc_client_state state;
|
||||
uint32_t pixfmt;
|
||||
uint32_t fourcc;
|
||||
struct rfb_pixel_format pixfmt;
|
||||
enum vnc_encodings encodings;
|
||||
LIST_ENTRY(vnc_client) link;
|
||||
size_t buffer_index;
|
||||
|
@ -57,6 +60,7 @@ struct vnc_server {
|
|||
uv_tcp_t tcp_handle;
|
||||
struct vnc_client_list clients;
|
||||
struct vnc_display display;
|
||||
struct vnc_framebuffer* fb;
|
||||
};
|
||||
|
||||
static const char* fourcc_to_string(uint32_t fourcc)
|
||||
|
@ -217,9 +221,9 @@ int rfb_pixfmt_from_fourcc(struct rfb_pixel_format *dst, uint32_t src) {
|
|||
bpp_32:
|
||||
dst->bits_per_pixel = 32;
|
||||
dst->depth = 24;
|
||||
dst->red_max = htons(0xff);
|
||||
dst->green_max = htons(0xff);
|
||||
dst->blue_max = htons(0xff);
|
||||
dst->red_max = 0xff;
|
||||
dst->green_max = 0xff;
|
||||
dst->blue_max = 0xff;
|
||||
break;
|
||||
case DRM_FORMAT_RGBA4444:
|
||||
case DRM_FORMAT_RGBX4444:
|
||||
|
@ -247,9 +251,9 @@ bpp_32:
|
|||
bpp_16:
|
||||
dst->bits_per_pixel = 16;
|
||||
dst->depth = 12;
|
||||
dst->red_max = htons(0x7f);
|
||||
dst->green_max = htons(0x7f);
|
||||
dst->blue_max = htons(0x7f);
|
||||
dst->red_max = 0x7f;
|
||||
dst->green_max = 0x7f;
|
||||
dst->blue_max = 0x7f;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
|
@ -320,18 +324,14 @@ int get_fourcc_depth(uint32_t fourcc)
|
|||
}
|
||||
}
|
||||
|
||||
/* Note: Pixel format is in network order */
|
||||
uint32_t rfb_pixfmt_to_fourcc(const struct rfb_pixel_format *fmt)
|
||||
{
|
||||
if (!fmt->true_colour_flag)
|
||||
return DRM_FORMAT_INVALID;
|
||||
|
||||
uint16_t red_max = ntohs(fmt->red_max);
|
||||
uint16_t green_max = ntohs(fmt->green_max);
|
||||
uint16_t blue_max = ntohs(fmt->blue_max);
|
||||
|
||||
/* Note: The depth value given by the client is ignored */
|
||||
int depth = max_values_to_depth(red_max, green_max, blue_max);
|
||||
int depth = max_values_to_depth(fmt->red_max, fmt->green_max,
|
||||
fmt->blue_max);
|
||||
if (depth < 0)
|
||||
return DRM_FORMAT_INVALID;
|
||||
|
||||
|
@ -368,7 +368,11 @@ static void send_server_init_message(struct vnc_client *client)
|
|||
msg->height = htons(display->height),
|
||||
msg->name_length = htonl(name_len),
|
||||
memcpy(msg->name_string, display->name, name_len);
|
||||
|
||||
rfb_pixfmt_from_fourcc(&msg->pixel_format, display->pixfmt);
|
||||
msg->pixel_format.red_max = htons(msg->pixel_format.red_max);
|
||||
msg->pixel_format.green_max = htons(msg->pixel_format.green_max);
|
||||
msg->pixel_format.blue_max = htons(msg->pixel_format.blue_max);
|
||||
|
||||
vnc__write((uv_stream_t*)&client->stream_handle, msg, size, NULL);
|
||||
|
||||
|
@ -406,9 +410,15 @@ static int on_client_set_pixel_format(struct vnc_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
client->pixfmt = rfb_pixfmt_to_fourcc(fmt);
|
||||
fmt->red_max = ntohs(fmt->red_max);
|
||||
fmt->green_max = ntohs(fmt->green_max);
|
||||
fmt->blue_max = ntohs(fmt->blue_max);
|
||||
|
||||
printf("SetPixelFormat: %s\n", fourcc_to_string(client->pixfmt));
|
||||
memcpy(&client->pixfmt, fmt, sizeof(client->pixfmt));
|
||||
|
||||
client->fourcc = rfb_pixfmt_to_fourcc(fmt);
|
||||
|
||||
printf("SetPixelFormat: %s\n", fourcc_to_string(client->fourcc));
|
||||
|
||||
return 4 + sizeof(struct rfb_pixel_format);
|
||||
}
|
||||
|
@ -453,7 +463,25 @@ static int on_client_fb_update_request(struct vnc_client *client)
|
|||
int height = ntohs(msg->height);
|
||||
|
||||
printf("framebuffer update: %d, %d. %d %d\n", x, y, width, height);
|
||||
// TODO
|
||||
|
||||
struct vnc_server *server = client->server;
|
||||
struct vnc_display *display = &server->display;
|
||||
struct vnc_framebuffer *fb = server->fb;
|
||||
|
||||
struct rfb_pixel_format server_fmt;
|
||||
rfb_pixfmt_from_fourcc(&server_fmt, server->display.pixfmt);
|
||||
|
||||
struct pixman_region16 region;
|
||||
pixman_region_init(®ion);
|
||||
|
||||
pixman_region_union_rect(®ion, ®ion, x, y, width, height);
|
||||
pixman_region_intersect_rect(®ion, ®ion, 0, 0, display->width,
|
||||
display->height);
|
||||
|
||||
zrle_encode_frame((uv_stream_t*)&client->stream_handle, &client->pixfmt,
|
||||
server->fb->addr, &server_fmt, fb->width, fb->height, ®ion);
|
||||
|
||||
pixman_region_fini(®ion);
|
||||
|
||||
return sizeof(*msg);
|
||||
}
|
||||
|
@ -643,13 +671,27 @@ failure:
|
|||
return -1;
|
||||
}
|
||||
|
||||
int main()
|
||||
int read_png_file(struct vnc_framebuffer* fb, const char *filename);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (!argv[1]) {
|
||||
printf("Missing argument\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct vnc_framebuffer fb;
|
||||
if (read_png_file(&fb, argv[1]) < 0) {
|
||||
printf("Failed to read png file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct vnc_server server = { 0 };
|
||||
server.fb = &fb;
|
||||
server.display.pixfmt = DRM_FORMAT_RGBX8888;
|
||||
server.display.width = 1024;
|
||||
server.display.height = 768;
|
||||
server.display.name = "Silly VNC";
|
||||
server.display.width = fb.width;
|
||||
server.display.height = fb.height;
|
||||
server.display.name = argv[1];
|
||||
|
||||
vnc_server_init(&server, "127.0.0.1", 5900);
|
||||
|
||||
|
|
6
util.h
6
util.h
|
@ -4,6 +4,12 @@
|
|||
#include <uv.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct vnc_framebuffer {
|
||||
void *addr;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct vnc_write_request {
|
||||
uv_write_t request;
|
||||
uv_write_cb on_done;
|
||||
|
|
16
zrle.c
16
zrle.c
|
@ -264,23 +264,23 @@ int zrle_encode_frame(uv_stream_t *stream,
|
|||
for (int i = 0; i < n_rects; ++i) {
|
||||
int x = box[i].x1;
|
||||
int y = box[i].y1;
|
||||
int width = box[i].x2 - x;
|
||||
int height = box[i].y2 - y;
|
||||
int box_width = box[i].x2 - x;
|
||||
int box_height = box[i].y2 - y;
|
||||
|
||||
struct rfb_server_fb_rect rect = {
|
||||
.encoding = htonl(RFB_ENCODING_ZRLE),
|
||||
.x = x,
|
||||
.y = x,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.x = htons(x),
|
||||
.y = htons(y),
|
||||
.width = htons(box_width),
|
||||
.height = htons(box_height),
|
||||
};
|
||||
|
||||
rc = vnc__write(stream, &rect, sizeof(head), NULL);
|
||||
rc = vnc__write(stream, &rect, sizeof(rect), NULL);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
rc = zrle_encode_box(stream, dst_fmt, src, src_fmt, x, y,
|
||||
width, height);
|
||||
box_width, box_height);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
}
|
||||
|
|
8
zrle.h
8
zrle.h
|
@ -5,6 +5,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
struct rfb_pixel_format;
|
||||
struct pixman_region16;
|
||||
|
||||
void pixel32_to_cpixel(uint8_t *restrict dst,
|
||||
const struct rfb_pixel_format* dst_fmt,
|
||||
|
@ -12,4 +13,11 @@ void pixel32_to_cpixel(uint8_t *restrict dst,
|
|||
const struct rfb_pixel_format* src_fmt,
|
||||
size_t bytes_per_cpixel, size_t len);
|
||||
|
||||
int zrle_encode_frame(uv_stream_t *stream,
|
||||
const struct rfb_pixel_format *dst_fmt,
|
||||
uint8_t *src,
|
||||
const struct rfb_pixel_format *src_fmt,
|
||||
int width, int height,
|
||||
struct pixman_region16 *region);
|
||||
|
||||
#endif /* _ZRLE_H_ */
|
||||
|
|
Loading…
Reference in New Issue