Rewrite vtv-player in C. - vtv-tools - virtual terminal video tools
(HTM) git clone git://bitreich.org/vtv-tools git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/vtv-tools
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Tags
(DIR) README
(DIR) LICENSE
---
(DIR) commit 3995532c578c1894a08817a4b6c463bcb892243f
(DIR) parent 97eae58b832d521bc35a23b2bec42e8ac957b233
(HTM) Author: Troels Henriksen <athas@sigkill.dk>
Date: Sun, 17 Sep 2023 15:00:16 +0200
Rewrite vtv-player in C.
This is much more efficient when the files are large.
Diffstat:
M .gitignore | 1 +
M Makefile | 8 +++++---
D bin/vtv-player | 39 -------------------------------
M man/vtv-player.1 | 2 ++
A src/vtv-player.c | 79 +++++++++++++++++++++++++++++++
M src/vtv-viewer.c | 8 --------
M src/vtv.h | 28 ++++++++++++++++++++--------
7 files changed, 107 insertions(+), 58 deletions(-)
---
(DIR) diff --git a/.gitignore b/.gitignore
@@ -1,2 +1,3 @@
bin/vtv-from-ff
bin/vtv-viewer
+bin/vtv-player
(DIR) diff --git a/Makefile b/Makefile
@@ -4,9 +4,10 @@ MANPREFIX ?= ${PREFIX}/share/man
CFLAGS?=-O -Wall -Wextra -pedantic
CC?=cc
-all: bin/vtv-from-ff bin/vtv-viewer
+all: bin/vtv-from-ff bin/vtv-viewer bin/vtv-player
bin/%: src/%.c src/vtv.h
+ @mkdir -p bin
$(CC) -o $@ $< $(CFLAGS)
install: all
@@ -18,6 +19,7 @@ install: all
@echo \# Installing manpages to ${MANPREFIX}/man1/
install -D -m 644 man/* ${MANPREFIX}/man1/
-.PHONY: all install
+.PHONY: all install clean
-clean: rm bin/vtv-from-ff bin/vtv-viewer
+clean:
+ rm -f bin/vtv-from-ff bin/vtv-viewer bin/vtv-player
(DIR) diff --git a/bin/vtv-player b/bin/vtv-player
@@ -1,39 +0,0 @@
-#!/bin/sh
-#
-# Play a single vtv file in an infinite loop.
-#
-# Copyright 2023 Troels Henriksen <athas@sigkill.dk>
-#
-# See LICENSE file for licensing information.
-
-trap 'clear; tput reset; exit 0' SIGINT
-
-fps=20
-
-if [ "$1" = "-r" ]; then
- fps=$2
- shift; shift;
-fi
-
-if [ $# -ne 1 ]; then
- echo "Usage: $0 FILE" >&2
- exit 1
-fi
-
-vtv="$1"
-frametime=$(echo "scale =2; 1 / $fps" | bc)
-framelines=25
-
-tput civis
-clear
-i=0
-nframes=$(echo "$(wc -l < "${vtv}")" / "$framelines" | bc)
-while true; do
- tput cup 0 0
- tail -n +$(echo "(1+${i} % ${nframes} * ${framelines})" | bc) "$vtv" | head -n $framelines
- i=$(($i + 1))
-
- userinput=""
- sleep $frametime
-done
-
(DIR) diff --git a/man/vtv-player.1 b/man/vtv-player.1
@@ -22,6 +22,8 @@ Plays a VTV file in the terminal. Loops until manually terminated.
.Bl -tag -width Ds
.It Fl r Ar fps
Show this many frames per second. Defaults to 20.
+.It Fl h Ar lines
+The number of lines in a frame. Defaults to 25.
.El
.
.Sh FORMAT
(DIR) diff --git a/src/vtv-player.c b/src/vtv-player.c
@@ -0,0 +1,79 @@
+// Copyright 2023 Troels Henriksen <athas@sigkill.dk>
+//
+// See LICENSE file for licensing information.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+
+#include "vtv.h"
+
+void hide_cursor() { printf("\033[?25l"); }
+void show_cursor() { printf("\033[?25h"); }
+void move(int x, int y) { printf("\033[%d;%dH", y, x); }
+void home() { printf("\033[;H"); }
+void clear_screen() { printf("\033[2J"); }
+void clear_line() { printf("\033[2K"); }
+void def() { printf("\033[0m"); }
+void reset() { printf("\033c"); }
+
+void sigint(int unused) {
+ (void)unused;
+ reset();
+ exit(0);
+}
+
+int main(int argc, char* argv[]) {
+ int fps = 20;
+ int frame_lines = 25;
+ const char *vtv_file;
+ struct vtv* vtv;
+
+ while (1) {
+ switch (getopt(argc, argv, "r:h:")) {
+ case 'r':
+ fps = atoi(optarg);
+ break;
+ case 'h':
+ frame_lines = atoi(optarg);
+ break;
+ case -1:
+ if (optind == argc-1) {
+ vtv_file = argv[optind];
+ goto done;
+ }
+ // fallthrough
+ default:
+ fprintf(stderr, "Usage: %s [-r INT] FILE\n", argv[0]);
+ exit(1);
+ }
+ }
+ done:
+ vtv = vtv_read_from_file(vtv_file);
+ if (vtv == NULL) {
+ fprintf(stderr, "%s: cannot read %s: %s\n",
+ argv[0], vtv_file, strerror(errno));
+ exit(1);
+ }
+
+ int num_frames = vtv->num_lines / frame_lines;
+
+ hide_cursor();
+ clear_screen();
+
+ int frame = 0;
+ signal(SIGINT, sigint);
+
+ while (1) {
+ useconds_t nap = 1000000.0 / fps;
+ frame = (frame+1) % num_frames;
+ home();
+ vtv_show_frame(vtv, stdout, frame, frame_lines,
+ "\033[0m MISSING LINE");
+ usleep(nap);
+ }
+ def();
+}
(DIR) diff --git a/src/vtv-viewer.c b/src/vtv-viewer.c
@@ -41,14 +41,6 @@ void clear_screen() { printf("\033[2J"); }
void clear_line() { printf("\033[2K"); }
void def() { printf("\033[0m"); }
-void fg_rgb(uint8_t r, uint8_t g, uint8_t b) {
- printf("\033[38;2;%d;%d;%dm", r, g, b);
-}
-
-void bg_rgb(uint8_t r, uint8_t g, uint8_t b) {
- printf("\033[48;2;%d;%d;%dm", r, g, b);
-}
-
struct {
int frame;
int lines_per_frame;
(DIR) diff --git a/src/vtv.h b/src/vtv.h
@@ -15,7 +15,7 @@ struct vtv {
char** lines;
};
-static void vtv_free(struct vtv* vtv) {
+void vtv_free(struct vtv* vtv) {
for (int i = 0; i < vtv->num_lines; i++) {
free(vtv->lines[i]);
}
@@ -24,7 +24,7 @@ static void vtv_free(struct vtv* vtv) {
}
// Returns nonzero on error.
-static int vtv_read_lines(FILE* f, char*** lines_out, int *num_lines_out) {
+int vtv_read_lines(FILE* f, char*** lines_out, int *num_lines_out) {
size_t n, num_lines = 0, capacity = 10;
char** lines = calloc(capacity, sizeof(char*));
ssize_t len;
@@ -47,11 +47,11 @@ static int vtv_read_lines(FILE* f, char*** lines_out, int *num_lines_out) {
// Show the given frame on the provided file. If there are not enough
// lines, show the provided line instead of the missing ones.
-static void vtv_show_frame(struct vtv* vtv,
- FILE* f,
- int frame,
- int lines_per_frame,
- const char *missing_line) {
+void vtv_show_frame(struct vtv* vtv,
+ FILE* f,
+ int frame,
+ int lines_per_frame,
+ const char *missing_line) {
for (int i = 0; i < lines_per_frame; i++) {
int j = frame*lines_per_frame + i;
if (j < vtv->num_lines) {
@@ -65,7 +65,7 @@ static void vtv_show_frame(struct vtv* vtv,
}
// Returns NULL on error.
-static struct vtv* vtv_read(FILE *f) {
+struct vtv* vtv_read(FILE *f) {
struct vtv* vtv = malloc(sizeof(struct vtv));
if (vtv_read_lines(f, &vtv->lines, &vtv->num_lines) == 0) {
return vtv;
@@ -74,3 +74,15 @@ static struct vtv* vtv_read(FILE *f) {
return NULL;
}
}
+
+// Returns NULL on error.
+struct vtv* vtv_read_from_file(const char *fname) {
+ FILE *f = fopen(fname, "r");
+ if (f == NULL) {
+ return NULL;
+ } else {
+ struct vtv* vtv = vtv_read(f);
+ fclose(f);
+ return vtv;
+ }
+}