Try serving a png

tight-png
Andri Yngvason 2019-08-25 19:10:35 +00:00 committed by Andri Yngvason
parent 24f0c4a0d4
commit 09dfb874b1
5 changed files with 168 additions and 28 deletions

84
pngfb.c 100644
View File

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

View File

@ -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(&region);
pixman_region_union_rect(&region, &region, x, y, width, height);
pixman_region_intersect_rect(&region, &region, 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, &region);
pixman_region_fini(&region);
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
View File

@ -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
View File

@ -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
View File

@ -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_ */