Skip to content

Releases: hitmux/hitvid

hitvid v1.2.0

08 Aug 02:56
c5ff1c4

Choose a tag to compare

Die Go-Implementierung ist der Shell-Version in fast jeder Hinsicht architektonisch überlegen. Die primäre Empfehlung ist, die Go-Version als primäre Codebasis zu übernehmen und weiterzuentwickeln, während das Shell-Skript als Prototyp betrachtet wird. Die Go-Version bietet eine solide Grundlage für hohe Leistung, Stabilität und zukünftige Erweiterbarkeit. Die folgenden Abschnitte beschreiben die Stärken und Schwächen beider Versionen und schlagen konkrete Verbesserungen für die Go-Implementierung vor.


1. Vergleichende Analyse

1.1 Architektur und Design

  • Go-Implementierung (hitvid_Go):

    • Stärken:
      • Struktur: Nutzt eine kompilierte, statisch typisierte Sprache, die für mehr Leistung und Typsicherheit sorgt.
      • Gleichzeitigkeit: Verwendet idiomatische Go-Konstrukte wie Goroutinen, Kanäle (channels), Mutexes und Bedingungsvariablen (sync.Cond). Dies ermöglicht eine saubere und effiziente Parallelverarbeitung von Frame-Rendering und Benutzereingaben.
      • Zustandsverwaltung: Der Zustand der Anwendung (z. B. Pause, Wiedergabegeschwindigkeit) wird zentral in Variablen verwaltet und durch einen Mutex geschützt, was die Komplexität reduziert und Race Conditions verhindert.
      • IPC (Inter-Process Communication): Gerenderte Frames werden direkt im Arbeitsspeicher (renderedFrames [][]byte) gehalten, was den extrem langsamen Festplatten-I/O des Shell-Skripts vermeidet.
  • Shell-Implementierung (hitvid_Shell):

    • Schwächen:
      • Komplexität: Mit über 600 Zeilen ist das Skript extrem komplex und schwer zu warten. Die Logik für die Prozessverwaltung, Fehlerbehandlung und Gleichzeitigkeit ist verschachtelt und unübersichtlich.
      • Gleichzeitigkeit: Die Parallelverarbeitung wird durch das manuelle Starten und Überwachen von Hintergrundprozessen (ffmpeg, chafa) realisiert. Die Synchronisation erfolgt durch sleep-Befehle und das ständige Überprüfen von Dateiexistenzen (while [ ! -f ... ]), was ineffizient und fehleranfällig ist.
      • IPC: Der gesamte Prozess basiert auf dem Schreiben und Lesen von Tausenden von einzelnen JPEG- und Textdateien auf der Festplatte. Dies ist der größte Leistungsengpass. Auch die Verwendung von /dev/shm (RAM-Disk) löst das grundlegende Problem des dateibasierten IPC nicht vollständig.

1.2 Leistung

  • Go-Implementierung:

    • Rendering-Pipeline: Die Verwendung eines Worker-Pools aus Goroutinen zum Rendern von Frames ist hocheffizient.
    • Overhead: Da es sich um ein kompiliertes Binary handelt, gibt es praktisch keinen Interpreter-Overhead während der Wiedergabe. Berechnungen erfolgen nativ und schnell.
    • Engpass: Der Hauptleistungsengpass ist die Geschwindigkeit von ffmpeg und chafa selbst, nicht die Orchestrierung durch das Go-Programm.
  • Shell-Implementierung:

    • Rendering-Pipeline: Der preload-Modus mit xargs -P ist für die Parallelisierung effektiv. Der stream-Modus mit seinem manuell verwalteten Daemon ist jedoch umständlich und langsam.
    • Overhead: Jeder Aufruf von awk, bc, date, tput und grep in der Wiedergabeschleife erzeugt einen neuen Prozess (fork/exec), was zu einem massiven Leistungsabfall führt.
    • Engpass: Der Festplatten-I/O für die Frame-Dateien ist der mit Abstand größte Engpass und begrenzt die maximal erreichbare Framerate erheblich.

1.3 Robustheit und Fehlerbehandlung

  • Go-Implementierung:

    • Graceful Shutdown: context.Context wird korrekt verwendet, um alle Goroutinen bei Benutzeraktionen (z. B. Beenden, nächstes Video) sauber zu beenden.
    • Fehlerbehandlung: Fehler werden explizit behandelt (if err != nil), was den Code vorhersehbar und robust macht.
    • Ressourcenmanagement: defer-Anweisungen stellen sicher, dass Ressourcen wie temporäre Verzeichnisse und der Terminalzustand zuverlässig bereinigt werden.
  • Shell-Implementierung:

    • Graceful Shutdown: Die cleanup-Funktion, die über trap aufgerufen wird, ist eine gute Vorgehensweise für Shell-Skripte, aber die korrekte Beendigung aller Kind- und Enkelprozesse ist komplex und nicht immer garantiert.
    • Fehlerbehandlung: Die Fehlerbehandlung ist verstreut und verlässt sich auf die Überprüfung von Exit-Codes ($?), was oft zu unbemerkten Fehlern führen kann.

2. Detaillierter Verbesserungsplan für die Go-Implementierung

Die Go-Version ist eine ausgezeichnete Grundlage. Die folgenden Verbesserungen zielen darauf ab, sie noch leistungsfähiger, ressourcenschonender und funktionsreicher zu machen.

2.1 Architektur & Speicherverwaltung

  • Problem: Die aktuelle Implementierung speichert alle gerenderten Frames im RAM (renderedFrames [][]byte). Bei langen oder hochauflösenden Videos kann dies zu einem extrem hohen Speicherverbrauch führen.
  • Empfehlung: Implementierung eines begrenzten Frame-Caches (Ringpuffer).
    • Aktion: Ersetzen Sie das unbegrenzte Slice renderedFrames durch eine Datenstruktur mit fester Größe (z. B. ein Puffer für 300 Frames).
    • Logik:
      1. Der Rendering-Worker schreibt einen neuen Frame in den Puffer.
      2. Der Wiedergabe-Loop liest Frames aus dem Puffer.
      3. Wenn der Puffer voll ist, pausiert der Dispatcher das Einreihen neuer Render-Jobs, bis die Wiedergabe Platz schafft.
      4. Bei einem Suchvorgang (seek) wird der Puffer geleert und mit Frames um den neuen Wiedergabepunkt herum neu befüllt.
    • Vorteil: Drastische Reduzierung des Speicherverbrauchs, wodurch die Anwendung auch bei langen Videos stabil läuft.

2.2 Leistung und Gleichzeitigkeit

  • Problem: Der globale stateMutex wird von mehreren Goroutinen (Wiedergabeschleife, Eingabehandler, Rendering-Worker) gleichzeitig verwendet, was zu potenziellen Latenzen führen kann.
  • Empfehlung: Verwendung von Kanälen für Benutzeraktionen.
    • Aktion: Erstellen Sie einen Kanal für Benutzeraktionen (z. B. userActionChan := make(chan string)).
    • Logik:
      1. Der handleInput-Handler sendet Aktionen wie "pause", "seek_forward", "speed_up" über den Kanal.
      2. Die Hauptwiedergabeschleife (playbackLoop) verwendet eine select-Anweisung, um entweder auf den nächsten Frame-Tick oder auf eine neue Benutzeraktion zu warten.
    • Vorteil: Entkoppelt die Eingabeverarbeitung von der Wiedergabelogik und reduziert die Sperrkonkurrenz, was zu einer reaktionsschnelleren Steuerung führt.

2.3 Fehlerbehandlung und Robustheit

  • Problem: Fehler, die während der ffmpeg-Extraktion auftreten, werden nicht an den Benutzer gemeldet, nachdem der Prozess gestartet wurde.
  • Empfehlung: Verbesserte Fehlerberichterstattung von ffmpeg.
    • Aktion: Überprüfen Sie den Rückgabefehler von ffmpegCmd.Wait() in der Goroutine, die auf das Ende von ffmpeg wartet.
    • Logik: Wenn ffmpegCmd.Wait() einen Fehler zurückgibt, bedeutet dies, dass ffmpeg mit einem Fehlercode beendet wurde. In diesem Fall sollte die Ausgabe, die im ffmpegErr-Puffer gesammelt wurde, im Terminal protokolliert werden, um dem Benutzer eine klare Fehlermeldung zu geben (z. B. "Codec nicht gefunden", "Datei beschädigt").

2.4 Funktionserweiterungen

  • Problem: Die Go-Version bietet keine flexiblen Skalierungsmodi wie das Shell-Skript (fit, fill, stretch).
  • Empfehlung: Implementierung erweiterter Skalierungsoptionen.
    • Aktion: Fügen Sie ein neues Befehlszeilen-Flag hinzu, z. B. -scale <mode>.
    • Logik: Basierend auf dem gewählten Modus muss die -vf-Option (Video-Filter) für ffmpeg dynamisch erstellt werden. Dies erfordert ähnliche Berechnungen wie im Shell-Skript, um das Seitenverhältnis zu berücksichtigen:
      • fit: scale=W:H:force_original_aspect_ratio=decrease
      • fill: scale=W:H:force_original_aspect_ratio=increase,crop=W:H
      • stretch: scale=W:H
    • Vorteil: Gibt dem Benutzer mehr Kontrolle über die Darstellung des Videos.

2.5 Codequalität

  • Problem: Globale Variablen für Konfiguration und Zustand machen den Code schwerer lesbar und testbar.
  • Empfehlung: Verwendung von Konfigurations- und Zustandsstrukturen.
    • Aktion:
      1. Führen Sie eine Config-Struktur ein, die alle Befehlszeilenoptionen enthält.
      2. Führen Sie eine Player-Struktur ein, die den gesamten Wiedergabezustand (Mutex, isPaused, currentFrameIndex usw.) kapselt.
    • Logik: Die main-Funktion initialisiert die Config-Struktur und übergibt sie an die playVideo-Funktion. Diese wiederum erstellt eine Player-Instanz. Zustandsänderungen erfolgen über Methoden auf dem Player-Objekt (z. B. player.Pause(), player.Seek()), die die Sperrung intern verwalten.
    • Vorteil: Verbessert die Kapselung, Lesbarkeit und Wartbarkeit des Codes erheblich.

hitvid v1.1.2

23 Jul 13:25
8b118f3

Choose a tag to compare

Modify the temporary directory creation logic:

  1. Try to use /dev/shm first to get the best performance.
  2. If the above method does not work, issue a warning and try to use $HOME/tmp. If it does not exist, try to create it.
  3. If neither of the above two methods is feasible, an error is reported.

The rest of the code is unchanged.

hitvid v1.1.1_Golang

22 Jul 10:00
0d6605e

Choose a tag to compare

hitvid v1.1.1_Golang Pre-release
Pre-release

Added a version written in Go language. Go is much faster than shell, and ffmpeg and chafa are built-in, no need to install, and it is faster.
Currently, the Go version is in the testing stage.

hitvid v1.1.1

01 Jun 03:19

Choose a tag to compare

Subject: feat: Enhance streaming playback, error handling, and quiet mode (v1.1.1)

This release introduces significant improvements to hitvid, focusing on more robust streaming playback, better error handling, and a refined user experience, especially when using the --quiet flag.

Key Changes & Improvements:

  1. Dedicated FFmpeg Monitoring Subshell (ffmpeg_monitor_subshell):

    • Old: FFmpeg progress monitoring and error logging were intertwined with the extract_frames_daemon function, sometimes leading to cluttered output or less reliable error detection.
    • New: A new, dedicated ffmpeg_monitor_subshell is introduced. This subshell runs in the background, specifically monitoring the FFmpeg process for health and logging any errors to a file.
    • Benefit: Decouples FFmpeg management from the main script flow, making the playback loop cleaner and more resilient. It also ensures FFmpeg errors are captured and reported even if the main script is busy rendering.
  2. Improved --quiet Mode Behavior:

    • Old: The --quiet flag suppressed some progress bars and interactive feedback, but not all, and some daemon messages could still appear. Interactive controls (like pause/seek) were also disabled in quiet mode.
    • New:
      • display_progress_bar now explicitly checks the QUIET flag, ensuring no progress bars are shown when quiet.
      • render_chafa_daemon no longer prints verbose progress messages to stderr during operation, respecting the quiet mode.
      • Crucially, interactive controls (Spacebar for pause/resume, arrow keys for seek/speed) now function even in --quiet mode. Only the visual feedback on the info line is suppressed.
      • The q key for quitting has been removed, standardizing on Ctrl+C for exiting, which is universally handled by the improved trap mechanism.
    • Benefit: Provides a truly "quiet" experience while retaining essential interactive control, offering a better user experience for those who prefer minimal output.
  3. Enhanced Error Handling and Cleanup:

    • Old: Cleanup was generally effective but could be improved, and trap handling was less specific.
    • New:
      • The cleanup function now explicitly attempts to terminate the new FFMPEG_MONITOR_PID in addition to FFmpeg and Chafa daemons.
      • trap commands are more specific (exit 130 for INT / Ctrl+C, exit 1 for TERM/EXIT), providing clearer exit codes.
      • Warning messages during playback (e.g., "Frame missing") are now printed cleanly above the info line using tput cup and tput el, preventing screen corruption.
    • Benefit: More robust and reliable termination of background processes, cleaner error reporting, and better overall script stability.
  4. More Accurate Video Information Parsing:

    • Old: get_video_info sometimes struggled with N/A or fractional duration/frame rate values from ffprobe, potentially leading to incorrect EXPECTED_TOTAL_FRAMES.
    • New: The logic for parsing VIDEO_DURATION_FLOAT and EXPECTED_TOTAL_FRAMES has been refined to better handle various ffprobe outputs (decimal, fractional, N/A), providing more accurate frame counts.
    • Benefit: Improves the reliability of frame extraction and playback duration, especially for videos with non-standard metadata.
  5. Streamlined Playback Initialization:

    • Old: The tput smcup; tput civis; clear commands were executed early, potentially clearing initial FFmpeg loading messages in stream mode.
    • New: These screen manipulation commands are now executed after any initial loading messages (including the FFmpeg progress bar from the monitor subshell) have been displayed and cleared.
    • Benefit: Ensures a smoother transition from loading to playback, preventing flicker or premature screen clearing.

This update significantly enhances hitvid's stability, user experience, and internal architecture, making it more reliable and pleasant to use.

hitvid v1.1.0

01 Jun 02:42
2764a85

Choose a tag to compare

hitvid Version Improvement Technical Report

Project Name: hitvid - Terminal Video Player

Version: From v1.0.2 to v1.1.0

Date: June 1, 2025

Core Maintainer: Hitmux


1. Overview

hitvid v1.1.0 represents a significant iteration in the hitvid project concerning performance and architectural stability. The primary goal of this version is to address the synchronization issues between Chafa rendering and video playback present in v1.0.2, and to significantly enhance the user experience, particularly playback fluidity under high frame rate and resource-constrained environments. By introducing Chafa rendering daemonization and optimizing the frame processing pipeline, we have successfully decoupled the rendering logic from the main playback loop, achieving a more truly streaming playback experience.

2. Key Improvements

2.1 Chafa Rendering Architecture Refactor

This is the most crucial improvement in v1.1.0.

  • v1.0.2 (Old Architecture):
    In v1.0.2, Chafa frame generation was initiated in the background as a parallel process via the render_all_chafa_frames_parallel & function. The main playback function play_chafa_frames relied on these background rendering processes to complete the generation of text frames. Although background execution was used, implicit synchronization points (via the file system) between the rendering and playback processes, and the eventual wait "$RENDER_PID" command, could still lead to blocking and stuttering during playback, especially if rendering speed could not keep up with playback speed.

    # v1.0.2 Core Rendering Startup Logic
    render_all_chafa_frames_parallel &
    RENDER_PID=$!
    # ...
    play_chafa_frames
    # ...
    wait "$RENDER_PID" # Wait for rendering process to complete
  • v1.1.0 (New Architecture):
    v1.1.0 introduces the render_chafa_daemon function, fundamentally changing how Chafa frames are generated. Now, render_chafa_daemon operates as an independent, long-running daemon process (CHAFA_RENDER_DAEMON_PID). It continuously reads the latest JPG frames from the JPG_FRAMES_DIR (generated by FFmpeg) and converts them in real-time into Chafa text frames, storing them in CHAFA_FRAMES_DIR.

    The main playback function play_chafa_frames no longer directly waits for rendering completion. Instead, it independently reads available text frames from CHAFA_FRAMES_DIR for display. This design achieves complete decoupling of rendering and playback, with play_chafa_frames acting as a "consumer" and render_chafa_daemon as a "producer."

    # v1.1.0 Core Rendering Startup Logic
    render_chafa_daemon "$EXPECTED_TOTAL_FRAMES" "$FFMPEG_PID" # Start the daemon
    # ...
    play_chafa_frames "$EXPECTED_TOTAL_FRAMES" # Play independently, reading from files output by the daemon
    # ...
    # At the end of playback, clean up the daemon
    if [[ -n "$CHAFA_RENDER_DAEMON_PID" ]] && ps -p "$CHAFA_RENDER_DAEMON_PID" > /dev/null; then
        kill -TERM "$CHAFA_RENDER_DAEMON_PID"
        wait "$CHAFA_RENDER_DAEMON_PID" 2>/dev/null
    fi
  • Technical Advantages:

    • High Throughput & Low Latency: The rendering process can work continuously, unblocked by the playback process, maximizing Chafa conversion throughput. The playback process can consume the latest rendered frames immediately, reducing display latency.
    • Playback Fluidity: Eliminates playback stuttering caused by rendering bottlenecks in the old version, achieving smoother video streams.
    • Improved Resource Utilization: The rendering process can continuously utilize idle CPU cycles in the background, improving overall system resource efficiency.
    • Robustness: A crash in the rendering process no longer directly leads to the failure of the main playback logic, enhancing application stability.

2.2 First Frame Pre-rendering Optimization

To provide more immediate visual feedback at the start of video playback, v1.1.0 improves the pre-rendering logic for the first frame.

  • v1.0.2: Simply called render_single_frame_for_xargs "$first_jpg_basename" and expected it to complete quickly. The first frame output went directly to standard output.

  • v1.1.0:

    • Added a loop (wait_first_jpg_count) to wait for the first JPG frame to be generated, ensuring the JPG file exists before attempting to render it.
    • Redirects the Chafa rendering result of the first frame directly to the first_txt_to_create file, rather than standard output. This ensures the first text file is available before playback.
    • Provides more explicit error and warning messages, e.g., when the FFmpeg process fails to generate the first JPG frame in time.
    # v1.1.0 First Frame Pre-rendering Logic
    wait_first_jpg_count=0
    while [ ! -f "$first_jpg_to_check" ] && [ "$wait_first_jpg_count" -lt 50 ] && [[ -n "$FFMPEG_PID" ]] && ps -p "$FFMPEG_PID" >/dev/null; do
        sleep 0.01
        wait_first_jpg_count=$((wait_first_jpg_count + 1))
    done
    
    if [ -f "$first_jpg_to_check" ]; then
        (chafa $CHAFA_OPTS_RENDER "$first_jpg_to_check" > "$first_txt_to_create")
        if [ $QUIET -eq 0 ] && [ -f "$first_txt_to_create" ]; then echo "First frame pre-rendered to $first_txt_to_create."; fi
    elif [ $QUIET -eq 0 ]; then
        echo "Warning: Could not pre-render first frame quickly. FFmpeg PID: ${FFMPEG_PID:-N/A}. File: $first_jpg_to_check"
    fi
  • Technical Advantages: Reduces the startup latency of video playback, improving the perceived responsiveness for the user.

2.3 Process ID (PID) Management and Cleanup

v1.1.0 introduces clearer PID management for background processes.

  • v1.0.2: Primarily focused on RENDER_PID.

  • v1.1.0: Explicitly defines and uses FFMPEG_PID and CHAFA_RENDER_DAEMON_PID as two key background process IDs. At the end of the script, kill -TERM and wait commands are used to ensure these background processes are correctly terminated and cleaned up, preventing zombie processes.

  • Technical Advantages: Enhances script robustness and resource management capabilities, reducing the risk of system resource leaks.

3. Future Work

  • "preload" Playback Mode: The PLAY_MODE="preload" option is commented out in the code but not yet implemented. Future work could include implementing this mode, where all Chafa frames are fully rendered before playback begins, suitable for short videos or scenarios requiring the highest possible fluidity.
  • More Granular Error Handling: Enhance error handling for abnormal exits of FFmpeg and Chafa processes, providing more user-friendly error messages.
  • Interactive Control Optimization: Further optimize the responsiveness and user experience of playback controls (pause, fast-forward, rewind).

hitvid v1.0.2

30 May 13:32

Choose a tag to compare

hitvid Script Modification Report

Overview

The new version of the hitvid script introduces significant functional enhancements and user experience (UX) optimizations over its predecessor. Key changes include the introduction of interactive playback controls (pause, seek forward/backward, speed adjustment), optimized frame processing performance (e.g., attempting to use the RAM disk /dev/shm for temporary file storage, FFmpeg pre-scaling), considerably improved user feedback mechanisms (such as progress bars for time-consuming operations), along with several code refactorings and enhancements to error handling.

Detailed Change Points

  1. New Interactive Playback Controls

    • Scope of Impact: Core logic of play_chafa_frames function, show_help message, new global variables.
    • Specific Changes:
      • In play_chafa_frames, user input is read non-blockingly using read -t.
      • Supported Controls:
        • Spacebar: Pause/Resume playback.
        • Right Arrow Key: Seek forward (by SEEK_SECONDS, default 5 seconds).
        • Left Arrow Key: Seek backward (by SEEK_SECONDS).
        • Up Arrow Key: Increase playback speed.
        • Down Arrow Key: Decrease playback speed.
      • New related global variables:
        • PAUSED: Flags the paused state.
        • ORIGINAL_FPS: Stores the user-defined or default original extraction frame rate.
        • CURRENT_FPS_MULTIPLIER_INDEX: Index to control the playback speed multiplier.
        • PLAYBACK_SPEED_MULTIPLIERS: Defines an array of available playback speed multipliers (e.g., 0.25x, 0.5x, 1.0x, 2.0x).
        • SEEK_SECONDS: Defines the seek duration in seconds.
      • show_help: Added an "Interactive Controls" section to explain these new features.
    • Purpose: Greatly enhances user flexibility and control while watching videos.
  2. Performance Optimizations

    • Temporary File Storage Optimization (setup_temp_dir):
      • Prioritizes creating the temporary directory in /dev/shm (tmpfs, a memory-based file system). If successful, this can significantly improve the read/write speed of frame files, especially for many small files.
      • If /dev/shm is unavailable or creation fails, it falls back to the traditional /tmp directory.
    • FFmpeg Pre-scaling (extract_frames):
      • New constants CHAR_PIXEL_WIDTH_APPROX and CHAR_PIXEL_HEIGHT_APPROX are introduced to estimate pixel dimensions corresponding to character cells.
      • Based on the target display character width (WIDTH) and height (HEIGHT), calculates target pixel dimensions for FFmpeg pre-scaling.
      • Adds a scale filter (and potentially crop depending on SCALE_MODE) to the ffmpeg command's -vf (video filter) option. This allows FFmpeg to scale frames to a size close to what Chafa requires during extraction.
      • Purpose: Reduces Chafa's scaling workload, potentially improving Chafa's rendering speed and the visual consistency of the final output.
    • Stream Mode First-Frame Pre-rendering (Main Execution Block for stream mode):
      • In stream mode, the script now attempts to synchronously render the first frame of the video before launching the background process to render the remaining frames.
      • Purpose: Reduces the waiting time for the user to see the first frame in stream mode, improving the startup experience.
  3. User Experience (UX) Enhancements

    • Progress Bar Display:
      • New helper function display_progress_bar added to generate and display text-based progress bars.
      • extract_frames: In non-quiet mode, uses the ffmpeg -progress option to output progress information to a file. The script reads this file to display a real-time progress bar for FFmpeg frame extraction.
      • render_all_chafa_frames_parallel: In preload mode and non-quiet mode, displays a rendering progress bar by polling the number of generated Chafa text frames.
      • play_chafa_frames: The information line during playback now includes a more intuitive progress bar showing the current playback position.
    • Clarification of FPS Parameter Semantics:
      • The help description for the --fps command-line option is updated to "Set extraction frames per second."
      • The ORIGINAL_FPS variable is introduced to store this extraction frame rate. The actual frame delay during playback is calculated based on this original FPS and the current playback speed multiplier.
    • More Detailed Output Information:
      • get_video_info: Output now includes the total number of input frames in the video (if provided by ffprobe).
      • extract_frames: Outputs the video filter options used by FFmpeg.
      • Richer informational messages for various stages (e.g., temporary directory location, renderer PID).
    • Terminal State Restoration (cleanup):
      • Added the stty sane command to ensure terminal settings are restored to a "sane" known-good state upon script exit (including abnormal exits).
    • Help Message (show_help):
      • Updated descriptions for -f, --fps and -s, --scale options for better accuracy.
      • Added a note about how -q, --quiet mode affects interactive feedback.
  4. Functional Improvements & Refactoring

    • Dependency Check (check_dependencies):
      • Added a dependency check for awk, as it's now used for floating-point arithmetic (e.g., calculating frame delay, comparing FPS values).
    • Argument Parsing and Validation:
      • The file existence check for VIDEO_PATH now correctly handles network stream URLs (e.g., http*, ftp*, rtmp*) and standard input (-), for which local file existence should not be checked.
      • Parameter validations involving floating-point numbers (e.g., FPS > 0, FPS > MAX_FPS) are now implemented using awk, which is more suitable for floating-point operations than Bash built-ins.
      • If an unknown option is provided, the script now shows the help message instead of directly exiting with an error.
    • Chafa Options and Environment:
      • The definition of the CHAFA_OPTS_RENDER variable is moved to the main execution flow, after extract_frames and before calling render_all_chafa_frames_parallel or render_single_frame_for_xargs.
      • In the render_all_chafa_frames_parallel function, when xargs is used to execute render_single_frame_for_xargs, variables like CHAFA_OPTS_RENDER, JPG_FRAMES_DIR, CHAFA_FRAMES_DIR, and QUIET are explicitly exported to ensure sub-shells correctly inherit these environment variables.
    • FFmpeg Invocation (extract_frames):
      • The ffmpeg command now includes the -nostdin option to prevent it from accidentally consuming standard input, which is crucial for the subsequent interactive key reading.
    • Playback Timing (play_chafa_frames):
      • The calculation of the sleep duration after each frame now considers the actual processing time for that frame (reading file, cat output, etc.), making the frame interval closer to the target frame rate.
      • frame_delay calculation is now based on ORIGINAL_FPS * PLAYBACK_SPEED_MULTIPLIER.
    • Error Handling:
      • In stream mode, if the background renderer process (RENDER_PID) terminates unexpectedly and the required frame file is missing, a more specific error message is displayed before exiting.
  5. Code Cleanup & Minor Adjustments

    • Removed the cleanup logic for XARGS_FIFO from the cleanup function, as it was mentioned in the old version but not actually used.
    • In render_single_frame_for_xargs, when the source JPG file doesn't exist, the check for QUIET is removed, and it directly returns an error code (as warnings go to stderr, and the progress bar is the primary user feedback).
    • Other minor updates to comments and code formatting for improved readability.

Conclusion

The new version of hitvid, by introducing interactive controls, optimizing performance, and improving the user interface, significantly enhances its usability and user-friendliness as a terminal video player. These modifications make the script more powerful, easier to operate, and provide a smoother experience.

hitvid v1.0.1

30 May 11:49
fd89be7

Choose a tag to compare

hitvid v1.0.1 Modification Report: Terminal Alternate Screen Buffer & Security Enhancements

The main contents of this modification include the implementation of the "alternate screen buffer" feature, addressing potential security vulnerabilities, enhancing code robustness, and adjusting default options to improve user experience.


I. Terminal Alternate Screen Buffer Feature Implementation

Goal:
Modify the hitvid script to play videos in the terminal's "alternate screen buffer." This provides a "full-screen" application-like experience where the video player occupies the entire terminal window without affecting previous command output. When the player exits, the original terminal screen and its scroll history will be restored.

Summary of Changes:

The core changes involve using tput commands to manage the terminal's screen buffers:

  • tput smcup: Switches to the alternate screen buffer.
  • tput rmcup: Switches back to the normal screen buffer.

These commands have been integrated into the script's playback and cleanup routines.

Detailed Modifications:

  1. play_chafa_frames() function:

    • Added tput smcup: At the beginning of this function, tput smcup is now called. This command instructs the terminal to switch to its alternate screen buffer before displaying any video playback content (such as the initial clear or the frames themselves).
    • Context of clear command: The existing clear command in this function now clears the alternate screen buffer, preparing it for video playback.
    • Removed Redundant Cleanup: tput cnorm (restore cursor) and the echo -e "\nPlayback complete." at the end of the function (which might implicitly clear the screen if it's the last output) have been adjusted or are now effectively handled by the cleanup function upon exit, ensuring a clean switch back to the normal screen. The "Playback complete" message now briefly appears on the alternate screen's info line, then cleanup takes over.
  2. cleanup() function:

    • Added tput rmcup: This command has been added to the cleanup function. It is responsible for switching the terminal from the alternate screen buffer back to the normal screen buffer.
    • Order of Operations: tput rmcup is called after tput cnorm (restoring the cursor). This ensures the cursor is visible first, then the screen is switched. Any subsequent echo commands within the cleanup function (e.g., "Cleaning up temporary files...") will now display on the restored normal terminal screen.
  3. trap command (in setup_temp_dir()):

    • Modified to include EXIT: The trap command has been updated to trap "cleanup; exit" INT TERM EXIT.
    • Adding EXIT is crucial. It ensures that the cleanup function (and thus tput cnorm and tput rmcup) is executed not only when the script is interrupted (e.g., INT via Ctrl+C, or TERM via kill) but also when the script terminates normally (e.g., when video playback completes and the script reaches its natural end or executes an exit 0 command).

Results:

  • When hitvid starts, initial messages (e.g., "Analyzing video file...") are displayed on the standard terminal screen.
  • Before video playback begins, the terminal switches to an alternate screen. The video will play within this "new" screen.
  • When playback ends or the script is interrupted, the cleanup function is triggered. This function restores the cursor, switches back to the normal terminal screen (restoring all prior output and scroll history), and then deletes temporary files.
  • The user experience is now similar to applications like vim, nano, or less, which use the alternate screen buffer to provide a dedicated interface without interfering with existing terminal content.

II. Security Vulnerability Fixes and Code Enhancements

This section details the security fixes and general code enhancements made to the hitvid script. The primary goals were to address potential command injection vulnerabilities and TOCTOU (Time-of-Check, Time-of-Use) race conditions in temporary file handling.

Overview of Addressed Vulnerabilities:

  1. Command Injection: The original script directly passed user-controlled input ($VIDEO_PATH) as arguments to external commands (ffmpeg, ffprobe) without proper separation. If an attacker could control the value of VIDEO_PATH (e.g., by crafting a filename starting with -), this could allow them to inject arbitrary command-line options or even execute arbitrary commands.
  2. TOCTOU (Time-of-Check, Time-of-Use) Race Condition: The temporary directory created with mktemp -d was subsequently removed using rm -rf "$TEMP_DIR". In a multi-user environment, a brief window exists between directory creation and the execution of the rm command, which a malicious actor could exploit to replace $TEMP_DIR with a symlink pointing to a sensitive directory (e.g., /home/user/.ssh), leading to unintended file deletion.

Detailed Modifications:

1. Command Injection Mitigation

  • Issue: The ffprobe, ffmpeg, and chafa commands were vulnerable to argument injection if $VIDEO_PATH or $jpg_path contained malicious characters or started with a hyphen (-).
  • Solution:
    • In the ffprobe and ffmpeg commands (get_video_info and extract_frames functions), -- (double-hyphen) has been added before the $VIDEO_PATH argument. The -- convention tells the command-line parser that all subsequent arguments are non-options (i.e., filenames), preventing them from being interpreted as command flags.
    • Similarly, in the chafa command (render_single_frame_for_xargs function), -- has also been added before the $jpg_path argument for consistency and best practice, even though $jpg_path is internally generated.

2. TOCTOU Vulnerability Mitigation in Temporary Directory Handling

  • Issue: The rm -rf "$TEMP_DIR" command in the cleanup() function was vulnerable to TOCTOU attacks.
  • Solution:
    • In setup_temp_dir():
      • Immediately after creating the temporary directory with mktemp -d, chmod 700 "$TEMP_DIR" has been added. This sets permissions to owner-only read, write, and execute, significantly reducing the window and opportunity for other users to tamper with the directory (e.g., by creating symlinks) before it's used or deleted.
    • In cleanup():
      • Robust validation has been implemented before executing rm -rf: if [ -d "$TEMP_DIR" ] && [[ "$TEMP_DIR" == /tmp/hitvid.* ]]. This check ensures that $TEMP_DIR still points to an actual directory and its path matches the expected pattern generated by mktemp (/tmp/hitvid.XXXXXX). If the path has been tampered with or is not a directory, a warning will be issued, and the deletion operation will be skipped.
      • Used rm -rf -- "$TEMP_DIR": Added -- to the rm command to prevent $TEMP_DIR (if maliciously modified to start with -) from being interpreted as an option for rm.
      • To be foolproof, the TEMP_DIR variable is now emptied after cleanup (TEMP_DIR="").
      • For consistency, -- has also been added for rm -f -- "$XARGS_FIFO", although XARGS_FIFO is not actually used in the currently provided script.

3. General Code Enhancements (Non-Security Related but Improves Robustness)

  • Improved Argument Parsing: The argument parsing loop has been made more robust, capable of handling various input scenarios, including the -- option separator.
  • Enhanced Input Validation: More specific error messages and show_help calls have been added for invalid command-line options and arguments, making the script easier to use and debug.
  • ffmpeg Exit Status Check: A check for the ffmpeg command's exit status has been added in extract_frames to provide clearer error reporting if frame extraction fails.
  • Use of printf: Some echo -e calls have been replaced with printf to improve portability across different shell environments, as echo -e behavior can vary.
  • URL Support: Explicitly stated that VIDEO_PATH can be an http or https URL, as ffmpeg supports this functionality.

Impact and Benefits:

These modifications significantly enhance the security of the hitvid script by preventing common attack vectors such as command injection and TOCTOU race conditions. The general code enhancements also make the application more robust, reliable, and user-friendly. Users can now run the script with greater confidence, knowing it is less susceptible to malicious input or environmental manipulation.


III. Default Option Modifications

Please compare the changes yourself, as they are not detailed here.

hitvid v1.0.0

30 May 08:50

Choose a tag to compare


hitvid Terminal Video Player Summary

hitvid is a Bash script-based terminal video player that leverages ffmpeg to extract video frames and chafa to render them as ASCII art, enabling direct video playback within your terminal.


Key Features

  • In-Terminal Playback: Watch videos directly in your terminal window.
  • Multiple Rendering Options: Supports custom FPS, scaling modes, color counts, dithering algorithms, and character sets.
  • Two Playback Modes:
    • preload (Default): Extracts and converts all video frames into Chafa text frames before playback begins, offering the smoothest experience but with a longer initial processing time.
    • stream: Starts playback while converting frames in the background. This allows for quicker initiation but might cause stuttering if rendering can't keep up.
  • Parallel Processing: Utilizes multi-core CPUs to speed up frame rendering.
  • Loop Playback and Quiet Mode are supported.
  • Automatic Cleanup of temporary files upon script exit.

Dependencies

You'll need ffmpeg, chafa, and tput installed. nproc and xargs are recommended for optimized performance.


Usage

Run the script using ./hitvid.sh [VIDEO_PATH] [OPTIONS]. It supports both local video file paths and direct video URLs.


Core Workflow

  1. General Steps: Parses arguments, checks dependencies, sets up a temporary directory, retrieves video info, and extracts JPG video frames using ffmpeg.
  2. preload Mode: All JPG frames are rendered in parallel into Chafa text frames before playback starts.
  3. stream Mode: Background parallel rendering of Chafa text frames occurs simultaneously with playback; the player waits if a required frame isn't ready.
  4. Cleanup: A trap mechanism ensures automatic deletion of temporary files and restoration of terminal settings upon script exit.

Notes and Troubleshooting

  • Performance: High-resolution or high-bitrate videos may be choppy, and terminal rendering capabilities can be a bottleneck.
  • Terminal Compatibility: Best results are seen with terminals that support ANSI escape sequences well (e.g., gnome-terminal, konsole, iTerm2).
  • Font: Monospaced fonts generally provide better character art display.
  • Temporary Files: Ensure sufficient space in your /tmp directory.
  • --threads Option: Setting this to your CPU core count is usually optimal.
  • Stuttering in Stream Mode: Try lowering FPS, reducing colors, increasing threads, or switching to preload mode.
  • Errors: Verify that all dependencies are installed and in your PATH, and check for corrupted video files.