You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.c 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. //#bx pkgs := libjpeg x11 xext
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <sys/shm.h>
  6. #include <X11/Xlib.h>
  7. #include <X11/Xutil.h>
  8. #include <X11/extensions/XShm.h>
  9. #include <jpeglib.h>
  10. #include <jerror.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <fcntl.h>
  14. #include <sys/socket.h>
  15. #include <string.h>
  16. #include <errno.h>
  17. #include <netinet/in.h>
  18. #include <arpa/inet.h>
  19. #include <netdb.h>
  20. static void *imgbuf = NULL;
  21. static size_t imgbuflen = 0;
  22. static size_t imgbufsize = 0;
  23. static void mem_jpeg_init_destination(j_compress_ptr cinfo) {
  24. if (imgbufsize == 0) {
  25. imgbufsize = 4 * 1024;
  26. imgbuf = malloc(imgbufsize);
  27. }
  28. imgbuflen = 0;
  29. cinfo->dest->next_output_byte = imgbuf;
  30. cinfo->dest->free_in_buffer = imgbufsize;
  31. }
  32. static boolean mem_jpeg_empty_output_buffer(j_compress_ptr cinfo) {
  33. imgbuflen = imgbufsize;
  34. imgbufsize *= 2;
  35. imgbuf = realloc(imgbuf, imgbufsize);
  36. cinfo->dest->next_output_byte = imgbuf + imgbuflen;
  37. cinfo->dest->free_in_buffer = imgbufsize - imgbuflen;
  38. printf("grew buffer to %zu\n", imgbufsize);
  39. return TRUE;
  40. }
  41. static void mem_jpeg_term_destination(j_compress_ptr cinfo) {
  42. imgbuflen = imgbufsize - cinfo->dest->free_in_buffer;
  43. }
  44. static void write_jpeg(XImage *img) {
  45. struct jpeg_compress_struct cinfo = {0};
  46. jpeg_create_compress(&cinfo);
  47. struct jpeg_destination_mgr dest = {0};
  48. dest.init_destination = mem_jpeg_init_destination;
  49. dest.empty_output_buffer = mem_jpeg_empty_output_buffer;
  50. dest.term_destination = mem_jpeg_term_destination;
  51. cinfo.dest = (struct jpeg_destination_mgr *)&dest;
  52. struct jpeg_error_mgr jerr;
  53. cinfo.err = jpeg_std_error(&jerr);
  54. cinfo.image_width = img->width;
  55. cinfo.image_height = img->height;
  56. cinfo.input_components = 4;
  57. cinfo.in_color_space = JCS_EXT_BGRX;
  58. jpeg_set_defaults(&cinfo);
  59. jpeg_start_compress(&cinfo, TRUE);
  60. for (int i = 0; i < cinfo.image_height; ++i) {
  61. JSAMPROW row = (unsigned char *)img->data + i * img->bytes_per_line;
  62. jpeg_write_scanlines(&cinfo, &row, 1);
  63. }
  64. jpeg_finish_compress(&cinfo);
  65. jpeg_destroy_compress(&cinfo);
  66. }
  67. static void upload_jpeg(XImage *img, int fd) {
  68. write_jpeg(img);
  69. uint32_t len = htonl((uint32_t)imgbuflen);
  70. write(fd, &len, sizeof(len));
  71. write(fd, imgbuf, imgbuflen);
  72. }
  73. int main(int argc, char **argv) {
  74. if (argc <= 1) {
  75. printf("Usage: %s <host> [port] [sleep time]\n", argv[0]);
  76. return 1;
  77. }
  78. char *host = argv[1];
  79. char *port;
  80. int sleeptime;
  81. if (argc >= 3) {
  82. port = argv[2];
  83. } else {
  84. port = "8099";
  85. }
  86. if (argc >= 4) {
  87. sleeptime = atoi(argv[3]);
  88. } else {
  89. sleeptime = 200;
  90. }
  91. printf("Connect %s:%s...\n", host, port);
  92. struct addrinfo hints = {
  93. .ai_family = AF_UNSPEC,
  94. .ai_socktype = SOCK_STREAM,
  95. .ai_protocol = 0,
  96. .ai_flags = AI_ADDRCONFIG,
  97. };
  98. struct addrinfo *info;
  99. if (getaddrinfo(host, port, &hints, &info) < 0) {
  100. perror("getaddrinfo");
  101. return 1;
  102. }
  103. int sockfd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
  104. if (sockfd < 0) {
  105. perror("socket");
  106. return 1;
  107. }
  108. if (connect(sockfd, info->ai_addr, info->ai_addrlen) < 0) {
  109. perror("connect");
  110. return 1;
  111. }
  112. freeaddrinfo(info);
  113. // This is useful
  114. if (getenv("DISPLAY") == NULL) {
  115. setenv("DISPLAY", ":0", 1);
  116. }
  117. Display *display = XOpenDisplay(NULL);
  118. if (display == NULL) {
  119. fprintf(stderr, "Failed to open display.\n");
  120. return 1;
  121. }
  122. Window root = XDefaultRootWindow(display);
  123. XWindowAttributes gwa;
  124. XGetWindowAttributes(display, root, &gwa);
  125. // Create shm image
  126. XShmSegmentInfo shminfo;
  127. XImage *image = XShmCreateImage(
  128. display, DefaultVisual(display, DefaultScreen(display)),
  129. 32, ZPixmap, NULL, &shminfo, gwa.width, gwa.height);
  130. // Attach shm image
  131. shminfo.shmid = shmget(IPC_PRIVATE,
  132. image->bytes_per_line * image->height,
  133. IPC_CREAT|0777);
  134. shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
  135. shminfo.readOnly = False;
  136. XShmAttach(display, &shminfo);
  137. while (1) {
  138. if (!XShmGetImage(display, root, image, 0, 0, AllPlanes)) {
  139. fprintf(stderr, "Failed to get image.\n");
  140. exit(EXIT_FAILURE);
  141. }
  142. upload_jpeg(image, sockfd);
  143. usleep(sleeptime * 1000);
  144. }
  145. XShmDetach(display, &shminfo);
  146. XDestroyImage(image);
  147. }