Browse Source

initial commit

master
Martin Dørum 3 years ago
commit
f606958fe9
2 changed files with 200 additions and 0 deletions
  1. 133
    0
      main.c
  2. 67
    0
      server.js

+ 133
- 0
main.c View File

@@ -0,0 +1,133 @@
//#bx pkgs := libjpeg x11 xext

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>
#include <jpeglib.h>
#include <jerror.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>

static void *imgbuf = NULL;
static size_t imgbuflen = 0;
static size_t imgbufsize = 0;

static void mem_jpeg_init_destination(j_compress_ptr cinfo) {
if (imgbufsize == 0) {
imgbufsize = 4 * 1024;
imgbuf = malloc(imgbufsize);
}

imgbuflen = 0;
cinfo->dest->next_output_byte = imgbuf;
cinfo->dest->free_in_buffer = imgbufsize;
}

static boolean mem_jpeg_empty_output_buffer(j_compress_ptr cinfo) {
imgbuflen = imgbufsize;
imgbufsize *= 2;
imgbuf = realloc(imgbuf, imgbufsize);

cinfo->dest->next_output_byte = imgbuf + imgbuflen;
cinfo->dest->free_in_buffer = imgbufsize - imgbuflen;
printf("grew buf to %zu, free space now %zu\n", imgbufsize, cinfo->dest->free_in_buffer);
return TRUE;
}

static void mem_jpeg_term_destination(j_compress_ptr cinfo) {
imgbuflen = imgbufsize - cinfo->dest->free_in_buffer;
}

static void write_jpeg(XImage *img) {
struct jpeg_compress_struct cinfo = {0};
jpeg_create_compress(&cinfo);
struct jpeg_destination_mgr dest = {0};
dest.init_destination = mem_jpeg_init_destination;
dest.empty_output_buffer = mem_jpeg_empty_output_buffer;
dest.term_destination = mem_jpeg_term_destination;
cinfo.dest = (struct jpeg_destination_mgr *)&dest;

struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);

cinfo.image_width = img->width;
cinfo.image_height = img->height;
cinfo.input_components = 4;
cinfo.in_color_space = JCS_EXT_BGRX;
jpeg_set_defaults(&cinfo);
jpeg_start_compress(&cinfo, TRUE);

for (int i = 0; i < cinfo.image_height; ++i) {
JSAMPROW row = (unsigned char *)img->data + i * img->bytes_per_line;
jpeg_write_scanlines(&cinfo, &row, 1);
}

jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
}

static void upload_jpeg(XImage *img, int fd) {
write_jpeg(img);
uint32_t len = (uint32_t)imgbuflen;
write(fd, &len, sizeof(len));
write(fd, imgbuf, len);
}

int main() {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
return 1;
}

struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
inet_aton("127.0.0.1", &addr.sin_addr);
if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("connect");
return 1;
}

Display *display = XOpenDisplay(NULL);
Window root = XDefaultRootWindow(display);
XWindowAttributes gwa;
XGetWindowAttributes(display, root, &gwa);

// Create shm image
XShmSegmentInfo shminfo;
XImage *image = XShmCreateImage(
display, DefaultVisual(display, DefaultScreen(display)),
32, ZPixmap, NULL, &shminfo, gwa.width, gwa.height);

// Attach shm image
shminfo.shmid = shmget(IPC_PRIVATE,
image->bytes_per_line * image->height,
IPC_CREAT|0777);
shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
shminfo.readOnly = False;
XShmAttach(display, &shminfo);

while (1) {
if (!XShmGetImage(display, root, image, 0, 0, AllPlanes)) {
fprintf(stderr, "Failed to get image.\n");
exit(EXIT_FAILURE);
}

upload_jpeg(image, sockfd);
sleep(1);
}

XShmDetach(display, &shminfo);
XDestroyImage(image);
}

+ 67
- 0
server.js View File

@@ -0,0 +1,67 @@
let http = require("http");
let net = require("net");

let tcpport = process.env["TCPPORT"] ? parseInt(process.env["TCPPORT"]) : 8080;
let httpport = process.env["HTTPPORT"] ? parseInt(process.env["HTTPPORT"]) : 8081;

let html = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>XRemoteView</title>
</head>
<body>
<img id="image" src="/image" style="object-fit: contain; height: 100vh; width: 100%;">
<script>
let img = document.getElementById("image");
let url = img.src;
setInterval(() => {
let rand = Math.floor(Math.random() * 1000000);
img.src = url + "?" + rand;
}, 1000);
</script>
</body>
</html>
`;

let imgdata = Buffer.alloc(0);

net.createServer(conn => {
console.log("Connection", conn.remoteAddress);

received = Buffer.alloc(0);
let hasLength = false;
let expectedLen = 0;
conn.on("data", data => {
received = Buffer.concat([received, data]);

while (true) {
if (!hasLength && received.length >= 4) {
expectedLen = received.readInt32LE(0);
hasLength = true;
}

if (hasLength && received.length >= expectedLen + 4) {
imgdata = received.slice(4, expectedLen + 4);
received = received.slice(expectedLen + 4);
hasLength = false;
} else {
break;
}
}
});
}).on("error", err => console.error(err)).listen(tcpport, "0.0.0.0");

http.createServer((req, res) => {
if (req.url.split("?")[0] == "/image") {
res.writeHead(200, {
"Content-Type": "image/jpeg",
"Refresh": "1",
});
res.end(imgdata);
} else {
res.writeHead(200);
res.end(html);
}
}).listen(httpport, "0.0.0.0");

Loading…
Cancel
Save