Skip to content

Instantly share code, notes, and snippets.

@ryancdotorg
Created December 12, 2022 14:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryancdotorg/7da388bf45de43f5563d3c0b9887008e to your computer and use it in GitHub Desktop.
Save ryancdotorg/7da388bf45de43f5563d3c0b9887008e to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: 0BSD OR MIT-0 OR Unlicense OR CC0-1.0+
// Copyright © 2022 Ryan Castellucci, no rights reserved
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#define FRAME_DELAY 36496350ULL
int64_t get_nanoseconds(void) {
int64_t r;
struct timespec ts;
r = clock_gettime(CLOCK_MONOTONIC, &ts);
if (r < 0)
return -1;
r = ts.tv_nsec + ts.tv_sec * 1000000000;
return r;
}
int main(int argc, char **argv) {
int fd, frame_len, dropped = 0;
struct stat statbuf;
unsigned char *input, *frame, *frame_end;
struct timespec ts_wait, ts_slept;
int64_t ns_now, ns_then, ns_wait;
if (argc != 2) {
fprintf(stderr, "Usage: %s filename\n", argv[0]);
return -1;
}
if ((fd = open(argv[1], O_RDONLY)) < 0) {
fprintf(stderr, "failed to open input file");
return 1;
}
if (fstat(fd, &statbuf) < 0) {
fprintf(stderr, "failed to stat input file");
return 1;
}
if ((input = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
fprintf(stderr, "failed to mmap input file");
return 1;
}
// move cursor and clear screen
fwrite("\033[1;1H\033[2J", 10, 1, stdout);
// initialize clocking
ns_then = get_nanoseconds();
frame = input;
while (frame < input + statbuf.st_size) {
if (!(frame_end = strstr(frame+1, "\033[H"))) {
if (!(frame_end = strstr(frame+1, "\033[m"))) break;
}
frame_len = frame_end - frame;
ns_now = get_nanoseconds();
ns_wait = ns_then - ns_now;
double delay = (double)ns_wait / 1000000000;
fprintf(stdout, "\033[G\033[2K next %7.4f (%u bytes, %u frames dropped)\033[G", delay, frame_len, dropped);
fflush(stdout);
if (ns_wait > 0) {
ts_wait.tv_sec = ns_wait / 1000000000;
ts_wait.tv_nsec = ns_wait % 1000000000;
nanosleep(&ts_wait, &ts_slept);
} else if (ns_wait < -10000000000) {
fprintf(stdout, "\033[2KYour connection is too slow to play this, sorry.\n");
break;
}
// drop or display frame
if (ns_wait > -100000000) {
fwrite(frame, frame_len, 1, stdout);
fwrite("\033[m", 3, 1, stdout);
fflush(stdout);
} else {
dropped += 1;
}
frame += frame_len;
ns_then += FRAME_DELAY;
}
// reset attributes
fwrite("\033[G\033[2K\033[0m", 11, 1, stdout);
fflush(stdout);
return 0;
}
/* vim: set ts=2 sw=2 et ai si: */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment