URI: 
       Rewrite vtv-player in C. - vtv-tools - virtual terminal video tools
  HTML 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
  HTML 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;
       +  }
       +}