commit 55382180a555831aa9740c9f8516897b978ba65f Author: Stu Leak Date: Wed Nov 5 11:45:14 2025 -0500 Initial commit: v0.1.0 - stable baseline diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a958bce --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +# VideoTools Makefile +# Cross-platform installer for Linux and Windows (Git Bash/WSL) + +PREFIX ?= /usr/local +INSTALL_DIR = $(PREFIX)/bin +DOC_DIR = $(PREFIX)/share/doc/videotools + +SCRIPT = video-tools.sh +DOCS = docs + +install: + @echo "Installing VideoTools..." + mkdir -p "$(INSTALL_DIR)" + cp "$(SCRIPT)" "$(INSTALL_DIR)/video-tools" + chmod +x "$(INSTALL_DIR)/video-tools" + @echo "Copied script to $(INSTALL_DIR)/video-tools" + + mkdir -p "$(DOC_DIR)" + cp -r "$(DOCS)"/* "$(DOC_DIR)/" + @echo "Documentation installed to $(DOC_DIR)" + +uninstall: + @echo "Removing VideoTools..." + rm -f "$(INSTALL_DIR)/video-tools" + rm -rf "$(DOC_DIR)" + @echo "VideoTools uninstalled." + +docs: + @echo "Opening documentation..." + @ls -1 $(DOCS) + +help: + @echo "Available targets:" + @echo " make install Install the toolkit system-wide" + @echo " make uninstall Remove the toolkit" + @echo " make docs List documentation files" + @echo " make help Show this message" diff --git a/config/config.json b/config/config.json new file mode 100644 index 0000000..ecb9ae6 --- /dev/null +++ b/config/config.json @@ -0,0 +1,13 @@ +{ + "version": "0.1.0", + "output_dir": "~/Videos", + "video_codec": "libx264", + "audio_codec": "aac", + "crf": 18, + "preset": "slow", + "audio_bitrate": "192k", + "default_filter": "lanczos", + "enable_faststart": true, + "auto_timestamp_fix": true, + "allow_overwrite": false +} diff --git a/docs/CLI_Functions.md b/docs/CLI_Functions.md new file mode 100644 index 0000000..a9ee50a --- /dev/null +++ b/docs/CLI_Functions.md @@ -0,0 +1,140 @@ +# CLI Function Reference + +This document describes the available commands in `video-tools.sh`. +Each command can be run from any terminal once the tool is installed. + +--- + +## Quick Reference + +| Command | Syntax | Description | +|----------|---------|-------------| +| `convert-single` | `video-tools convert-single ` | Converts a single video to MP4. | +| `convert-multiple` | `video-tools convert-multiple ... ` | Combines multiple video files into one MP4. | + +All outputs are saved in your default `~/Videos` folder. + +--- + +## Command Details + +### 1. convert-single + +**Purpose** +Convert a single input video file into an MP4 with modern compression and audio standards. + +**Usage** +```bash +video-tools convert-single +``` + +**Example** +```bash +video-tools convert-single \ +"/run/media/user/Linux/MyData/Videos/Example Collection/Example Movie Part1.avi" \ +"Example Movie.mp4" +``` + +**Output** +``` +/home/user/Videos/Example Movie.mp4 +``` + +**Behavior** +- Converts older formats (AVI, MPG, MOV, MKV, etc.) into MP4. +- Ensures output uses the H.264 codec (libx264) and AAC audio. +- Rebuilds timestamps to avoid sync issues. +- Adds `+faststart` flag for quicker playback when streamed or loaded in players. + +**When to use** +- When you want to upgrade old videos to a more efficient format. +- When a single video won’t play on mobile or modern devices. +- To reduce file size without losing visible quality. + +--- + +### 2. convert-multiple + +**Purpose** +Combine several clips or discs into one MP4 output file. + +**Usage** +```bash +video-tools convert-multiple ... +``` + +**Example** +```bash +video-tools convert-multiple \ +"/run/media/user/Linux/MyData/Videos/Example Collection/Example Movie Part1.avi" \ +"/run/media/user/Linux/MyData/Videos/Example Collection/Example Movie Part2.avi" \ +"/run/media/user/Linux/MyData/Videos/Example Collection/Example Movie Part3.avi" \ +"Example Movie Combined.mp4" +``` + +**Output** +``` +/home/user/Videos/Example Movie Combined.mp4 +``` + +**Behavior** +- Reads all listed files in order and merges them seamlessly. +- Each input is re-encoded using the same H.264/AAC settings. +- Temporary file list is automatically created and deleted. +- Logs detailed FFmpeg progress to the terminal. + +**When to use** +- When combining multi-part video discs, episodes, or scene splits. +- When creating a single playable MP4 from segmented source material. + +--- + +## Return Codes + +| Code | Meaning | +|------|----------| +| 0 | Success | +| 1 | Invalid syntax or missing arguments | +| 2 | FFmpeg execution error | + +--- + +## Common Issues + +| Symptom | Cause | Fix | +|----------|--------|----| +| Conversion fails immediately | Input path invalid | Ensure file path is correct and quoted | +| Merge creates sync issues | Source files differ in resolution or frame rate | Convert each to MP4 first, then merge | +| Output not found | FFmpeg failed silently | Check terminal logs for permission or codec errors | + +--- + +## Planned Additions + +| Command | Description | +|----------|-------------| +| `convert-batch` | Convert every video in a folder automatically | +| `upscale-video` | Upscale videos to 1080p or 4K using `lanczos` or ML filters | +| `compress-video` | Recompress MP4s using HEVC or AV1 for smaller storage | +| `video-info` | Quick summary of resolution, codec, and bitrate | + +--- + +## Technical Summary + +### Conversion Logic +- Uses FFmpeg with explicit input and output flags: + ``` + ffmpeg -fflags +genpts -i "input" -c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k -movflags +faststart "output" + ``` +- `-fflags +genpts` regenerates presentation timestamps (avoids "Non-monotonic DTS" errors). +- Re-encoding ensures compatibility and stable playback. + +### File Safety +- Original files are untouched. +- All intermediate list files are removed automatically. +- FFmpeg handles SIGINT (Ctrl+C) gracefully—partially written files are still playable. + +--- + +End of File diff --git a/docs/Conversion_Settings.md b/docs/Conversion_Settings.md new file mode 100644 index 0000000..13ddd35 --- /dev/null +++ b/docs/Conversion_Settings.md @@ -0,0 +1,99 @@ +# Conversion Settings + +This file documents the default FFmpeg parameters used in `video-tools.sh` and explains why they are chosen. + +--- + +## Output Format +All conversions produce: +``` +Format: MP4 +Container: MPEG-4 Part 14 +Video Codec: H.264 (libx264) +Audio Codec: AAC +``` + +MP4 was chosen because: +- It’s universally supported across modern devices. +- It balances size and compatibility well. +- H.264 encoding provides excellent quality at smaller bitrates. + +--- + +## Default Parameters + +| Parameter | Value | Purpose | +|------------|--------|----------| +| `-c:v libx264` | H.264 video encoding | Modern, efficient codec with wide hardware support | +| `-crf 18` | Constant Rate Factor | Maintains near-lossless visual quality; lower = better | +| `-preset slow` | Encoding preset | Improves compression efficiency; trades some speed | +| `-c:a aac` | Audio codec | Standard high-quality stereo audio | +| `-b:a 192k` | Audio bitrate | Balances fidelity and file size | +| `-movflags +faststart` | MP4 optimization | Enables faster playback start in players or web streams | +| `-fflags +genpts` | Timestamp repair | Regenerates timestamps on older AVI/MPEG inputs | + +--- + +## Quality vs. File Size + +The CRF scale (used by FFmpeg) defines quality and compression balance: + +| CRF | Description | Typical Use | +|------|-------------|--------------| +| 14–16 | Near lossless | Archival or professional mastering | +| 18–20 | High quality | Everyday use, visually lossless | +| 21–24 | Medium quality | Small file sizes, light compression | +| 25+ | Low quality | Fast compression, heavy size reduction | + +The default of **CRF 18** keeps visual clarity virtually identical to the original while cutting most AVI or MPG files to **40–60% smaller** sizes. + +--- + +## Why Preset "slow" + +The preset defines encoding effort vs. compression efficiency. +Options range from `ultrafast` → `veryslow`. + +- **slow** provides strong compression without extreme CPU time. +- Encoding speed is roughly 2–3× real-time on a midrange CPU. +- File sizes are typically 10–20% smaller than `medium` preset at the same quality. + +--- + +## Audio Strategy + +AAC at 192k is chosen for: +- Wide playback compatibility (phones, TVs, players). +- Transparent stereo sound for most sources. +- Reasonable storage size (~2MB/minute of stereo audio). + +If future needs arise, the tool can later support: +- `-c:a copy` for untouched audio streams. +- `-b:a 320k` for high-fidelity preservation. + +--- + +## Color Space & Scaling + +No scaling is applied by default. +The video retains original resolution and color profile. + +Upscaling and filtering will be handled in a separate command (`upscale-video`) in future versions, with support for: +- FFmpeg’s `scale` and `zscale` filters. +- `lanczos` resampling (for sharp, clean upscale). +- Optional integration with ML-based models (Real-ESRGAN, waifu2x). + +--- + +## Future Additions + +| Planned Setting | Description | +|------------------|-------------| +| `upscale-mode` | Default scaling filter for upscaling tasks | +| `hevc-mode` | Switch to H.265 (libx265) for smaller files | +| `audio-pass` | Option to skip audio re-encoding | +| `config.json` | User-editable file to override default values | + +--- + +End of File diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..d007b43 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,137 @@ +# Video Tools CLI + +A simple command-line utility for video conversion and merging using FFmpeg. +Designed for personal use and sharing with friends. +Works on both Linux and Windows (via Git Bash or WSL). + +--- + +## Overview + +This tool provides two main commands: + +| Command | Description | +|----------|-------------| +| `convert-single` | Converts a single video file to MP4 using modern compression. | +| `convert-multiple` | Combines multiple video files into one high-quality MP4. | + +All output files are saved in your `~/Videos` directory by default. + +--- + +## Requirements + +### Linux +Install FFmpeg with your package manager: +```bash +sudo pacman -S ffmpeg # For Arch or Garuda +sudo apt install ffmpeg # For Debian or Ubuntu +``` + +### Windows +1. Install FFmpeg from https://ffmpeg.org/download.html +2. Use **Git Bash** or **WSL** to run the script. + +--- + +## Installation + +1. Clone or copy the repository: + ```bash + git clone https://github.com/YourName/VideoTools.git + cd VideoTools + ``` + +2. Make the script executable: + ```bash + chmod +x video-tools.sh + ``` + +3. (Optional) Add it to PATH: + ```bash + sudo ln -s ~/VideoTools/video-tools.sh /usr/local/bin/video-tools + ``` + +You can now run it globally: +```bash +video-tools convert-single "input.avi" "output.mp4" +``` + +--- + +## Default Settings + +| Setting | Value | Description | +|----------|--------|-------------| +| Output directory | `~/Videos` | All results are stored here | +| Video codec | `libx264` | High-quality H.264 encoding | +| Audio codec | `aac` | High-quality AAC stereo audio | +| Quality (CRF) | 18 | Visually lossless quality | +| Preset | slow | Balances speed and compression | +| Audio bitrate | 192k | High-quality stereo output | + +These defaults prioritize quality while still reducing file sizes compared to older formats such as AVI or MPG. + +--- + +## Example Conversions + +### Convert a single AVI file + +```bash +video-tools convert-single \ +"/run/media/stu/Linux/MyData/Videos/Example Collection/Example Movie Part1.avi" \ +"Example Movie.mp4" +``` + +Output: +``` +/home/stu/Videos/Example Movie.mp4 +``` + +--- + +### Combine multiple AVI parts into one MP4 + +```bash +video-tools convert-multiple \ +"/run/media/stu/Linux/MyData/Videos/Example Collection/Example Movie Part1.avi" \ +"/run/media/stu/Linux/MyData/Videos/Example Collection/Example Movie Part2.avi" \ +"/run/media/stu/Linux/MyData/Videos/Example Collection/Example Movie Part3.avi" \ +"Example Movie Combined.mp4" +``` + +Output: +``` +/home/stu/Videos/Example Movie Combined.mp4 +``` + +--- + +## Troubleshooting + +| Issue | Cause | Solution | +|--------|--------|----------| +| `command not found` | Script not in PATH | Use full path or add symlink to `/usr/local/bin` | +| `ffmpeg not found` | FFmpeg not installed | Install FFmpeg using your package manager | +| `Permission denied` | Script not executable | Run `chmod +x video-tools.sh` | +| Merge fails | Input files have mismatched codecs | Convert each input to MP4 first, then merge | + +--- + +## Roadmap + +| Feature | Status | +|----------|--------| +| convert-single | ✅ Done | +| convert-multiple | ✅ Done | +| upscale-video | 🔜 Planned | +| batch conversion | 🔜 Planned | +| automatic format detection | 🔜 Planned | + +--- + +## License + +Free for personal use. +You can modify or share this tool with anyone. diff --git a/docs/Upscale.md b/docs/Upscale.md new file mode 100644 index 0000000..8e3057a --- /dev/null +++ b/docs/Upscale.md @@ -0,0 +1,71 @@ +# Upscale Module (Planned) + +The `upscale-video` command will provide loss-minimized video upscaling. + +--- + +## Overview + +This module will allow upscaling of existing videos to higher resolutions such as: +- 720p (HD) +- 1080p (Full HD) +- 2160p (4K) + +It will use FFmpeg’s native scaling filters first and optionally integrate machine learning tools later. + +--- + +## Planned Syntax + +```bash +video-tools upscale-video --scale 1920x1080 +``` + +Optional parameters: +``` +--scale Set explicit resolution +--filter Choose scaling filter (lanczos, bicubic, spline36) +--hevc Encode using H.265 for smaller output +--keep-audio Copy original audio stream without re-encoding +``` + +--- + +## Default Behavior + +If no resolution is provided, the tool will upscale intelligently to the nearest standard resolution above the input video. + +Example: +- Input: 960×540 → Output: 1280×720 +- Input: 1280×720 → Output: 1920×1080 + +--- + +## Technical Notes + +### FFmpeg Filter Example + +```bash +ffmpeg -i input.mp4 -vf scale=1920:1080:flags=lanczos \ +-c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k output_1080p.mp4 +``` + +- `scale=1920:1080:flags=lanczos` → high-quality resampling +- `lanczos` offers sharp, low-artifact upscale +- Later versions may support `zscale` or ML-based filters + +--- + +## Planned Features + +| Feature | Status | +|----------|--------| +| FFmpeg scaler (lanczos) | 🔜 Planned | +| ML-based upscaling (Real-ESRGAN / waifu2x) | 🚧 Research | +| Auto resolution detection | 🔜 Planned | +| GPU acceleration support | 🔜 Planned | +| Configurable presets | 🔜 Planned | + +--- + +End of File diff --git a/video-tools.sh b/video-tools.sh new file mode 100755 index 0000000..f5c1d1e --- /dev/null +++ b/video-tools.sh @@ -0,0 +1,169 @@ +#!/usr/bin/env bash +# +# Simple FFmpeg CLI Toolset +# ------------------------- +# Provides easy commands for single or multi-file video conversion. +# Works on Linux and Windows (Git Bash / WSL) as long as ffmpeg is installed. +# + +set -euo pipefail + +# ========================================================== +# Configuration system +# ========================================================== +CONFIG_FILE="$(dirname "$0")/config/config.json" + +# ------------------------- +# Default configuration +# ------------------------- +OUTPUT_DIR="$HOME/Videos" +VIDEO_CODEC="libx264" +AUDIO_CODEC="aac" +CRF="18" # lower = higher quality +PRESET="slow" # slower = better compression +AUDIO_BITRATE="192k" +VERSION="0.1.0" + +# ========================================================== +# Utility: Colour logging +# ========================================================== +RED="\033[31m" +YELLOW="\033[33m" +GREEN="\033[32m" +BLUE="\033[34m" +NC="\033[0m" # reset + +info() { echo -e "${BLUE}[INFO]${NC} $*"; } +success() { echo -e "${GREEN}[OK]${NC} $*"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } + +# ========================================================== +# Check dependencies early +# ========================================================== +if ! command -v ffmpeg >/dev/null 2>&1; then + error "ffmpeg is not installed or not in PATH." + exit 1 +fi + +if [[ -f "$CONFIG_FILE" ]] && command -v jq >/dev/null 2>&1; then + info "Loading configuration from: $CONFIG_FILE" + OUTPUT_DIR="$(eval echo "$(jq -r '.output_dir // empty' "$CONFIG_FILE")")" || true + VIDEO_CODEC="$(jq -r '.video_codec // empty' "$CONFIG_FILE" 2>/dev/null || echo "$VIDEO_CODEC")" + AUDIO_CODEC="$(jq -r '.audio_codec // empty' "$CONFIG_FILE" 2>/dev/null || echo "$AUDIO_CODEC")" + CRF="$(jq -r '.crf // empty' "$CONFIG_FILE" 2>/dev/null || echo "$CRF")" + PRESET="$(jq -r '.preset // empty' "$CONFIG_FILE" 2>/dev/null || echo "$PRESET")" + AUDIO_BITRATE="$(jq -r '.audio_bitrate // empty' "$CONFIG_FILE" 2>/dev/null || echo "$AUDIO_BITRATE")" + VERSION="$(jq -r '.version // empty' "$CONFIG_FILE" 2>/dev/null || echo "$VERSION")" +elif [[ ! -f "$CONFIG_FILE" ]]; then + warn "No config.json found — using internal defaults." +else + warn "jq not found — skipping config.json parsing." +fi + +mkdir -p "$OUTPUT_DIR" || { error "Failed to create output directory $OUTPUT_DIR"; exit 1; } + +# ========================================================== +# Header output +# ========================================================== +print_header() { + echo "----------------------------------------------" + echo "Video Tools v$VERSION" + echo "Output directory: $OUTPUT_DIR" + echo "Video codec : $VIDEO_CODEC" + echo "Audio codec : $AUDIO_CODEC" + echo "CRF : $CRF" + echo "Preset : $PRESET" + echo "Audio rate : $AUDIO_BITRATE" + echo "----------------------------------------------" +} + +# ========================================================== +# Convert one file +# ========================================================== +convert_single() { + local input="$1" + local output_name="$2" + local output_path="$OUTPUT_DIR/$output_name" + + print_header + info "Converting single video..." + info "Input : $input" + info "Output: $output_path" + + if [[ ! -f "$input" ]]; then + error "Input file not found: $input" + exit 1 + fi + + ffmpeg -hide_banner -loglevel info -fflags +genpts \ + -i "$input" \ + -c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \ + -c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \ + "$output_path" || { error "Conversion failed."; exit 1; } + + success "Conversion complete: $output_path" +} + +# ========================================================== +# Combine multiple files +# ========================================================== +convert_multiple() { + local args=("$@") + local output_name="${args[-1]}" + unset 'args[-1]' + local list_file + list_file=$(mktemp) + local output_path="$OUTPUT_DIR/$output_name" + + print_header + info "Combining multiple videos..." + for input in "${args[@]}"; do + if [[ ! -f "$input" ]]; then + error "Missing input file: $input" + rm -f "$list_file" + exit 1 + fi + echo "file '$input'" >> "$list_file" + info " + Added: $input" + done + echo "----------------------------------------------" + + ffmpeg -hide_banner -loglevel info -f concat -safe 0 -i "$list_file" \ + -c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \ + -c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \ + "$output_path" || { error "Merge failed."; rm -f "$list_file"; exit 1; } + + rm -f "$list_file" + success "Combined video created: $output_path" +} + +# ========================================================== +# Dispatcher +# ========================================================== +case "${1:-}" in + convert-single) + shift + if [[ $# -ne 2 ]]; then + error "Usage: $0 convert-single " + exit 1 + fi + convert_single "$@" + ;; + convert-multiple) + shift + if [[ $# -lt 3 ]]; then + error "Usage: $0 convert-multiple ... " + exit 1 + fi + convert_multiple "$@" + ;; + *) + echo "Video Tools v$VERSION" + echo "Usage:" + echo " $0 convert-single " + echo " $0 convert-multiple ... " + echo "" + echo "All outputs will be saved in: $OUTPUT_DIR" + ;; +esac