Compare commits

...

3 Commits

9 changed files with 880 additions and 344 deletions

View File

@ -1,37 +1,92 @@
# VideoTools Makefile # Cross-platform installer for VideoTools (Linux / Windows via Git Bash or WSL)
# Cross-platform installer for Linux and Windows (Git Bash/WSL)
PREFIX ?= /usr/local PREFIX ?= /usr/local
INSTALL_DIR = $(PREFIX)/bin INSTALL_DIR = $(PREFIX)/bin
DOC_DIR = $(PREFIX)/share/doc/videotools DOC_DIR = $(PREFIX)/share/doc/videotools
SCRIPT = video-tools.sh SCRIPT = video-tools.sh
DOCS = docs DOCS = docs
VERSION_FILE = VERSION
install: # ------------------------
# Installation
# ------------------------
install: verify
@echo "Installing VideoTools..." @echo "Installing VideoTools..."
mkdir -p "$(INSTALL_DIR)" @mkdir -p "$(INSTALL_DIR)"
cp "$(SCRIPT)" "$(INSTALL_DIR)/video-tools" @install -m 755 "$(SCRIPT)" "$(INSTALL_DIR)/video-tools"
chmod +x "$(INSTALL_DIR)/video-tools" @echo "✔ Installed script to $(INSTALL_DIR)/video-tools"
@echo "Copied script to $(INSTALL_DIR)/video-tools"
mkdir -p "$(DOC_DIR)" @mkdir -p "$(DOC_DIR)"
cp -r "$(DOCS)"/* "$(DOC_DIR)/" @cp -r "$(DOCS)"/* "$(DOC_DIR)/"
@echo "Documentation installed to $(DOC_DIR)" @echo "✔ Installed documentation to $(DOC_DIR)"
@if [ -f "$(VERSION_FILE)" ]; then \
VERSION=$$(cat $(VERSION_FILE)); \
echo "✔ VideoTools v$$VERSION installed successfully."; \
else \
echo "⚠ Version file not found. Install completed without version info."; \
fi
@echo ""
# ------------------------
# Uninstall
# ------------------------
uninstall: uninstall:
@echo "Removing VideoTools..." @echo "Removing VideoTools..."
rm -f "$(INSTALL_DIR)/video-tools" @rm -f "$(INSTALL_DIR)/video-tools"
rm -rf "$(DOC_DIR)" @rm -rf "$(DOC_DIR)"
@echo "VideoTools uninstalled." @echo "✔ VideoTools uninstalled."
# ------------------------
# Verification
# ------------------------
verify:
@echo "Checking environment..."
@if ! command -v ffmpeg >/dev/null 2>&1; then \
echo "✖ FFmpeg not found. Please install FFmpeg before continuing."; \
exit 1; \
else \
echo "✔ FFmpeg found."; \
fi
@if ! command -v ffprobe >/dev/null 2>&1; then \
echo "✖ FFprobe not found. Please install FFprobe before continuing."; \
exit 1; \
else \
echo "✔ FFprobe found."; \
fi
@echo "✔ Environment OK."
@echo ""
# ------------------------
# Documentation
# ------------------------
docs: docs:
@echo "Opening documentation..." @echo "Available documentation files:"
@ls -1 $(DOCS) @ls -1 "$(DOCS)" | sed 's/^/ - /'
# ------------------------
# Help
# ------------------------
help: help:
@echo "Available targets:" @echo "VideoTools Makefile — available targets:"
@echo " make install Install the toolkit system-wide" @echo ""
@echo " make uninstall Remove the toolkit" @echo " make install Install the toolkit system-wide"
@echo " make docs List documentation files" @echo " make uninstall Remove all installed files"
@echo " make help Show this message" @echo " make verify Check FFmpeg, FFprobe, and environment"
@echo " make docs List available documentation"
@echo " make help Show this message"
@echo ""
@echo "Installation directories:"
@echo " Script: $(INSTALL_DIR)"
@echo " Docs : $(DOC_DIR)"
@echo ""
@echo "Note: Windows users can run 'make' via Git Bash or WSL."
# ------------------------
# End of File
# ------------------------

1
VERSION Normal file
View File

@ -0,0 +1 @@
0.1.1

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.0", "version": "0.1.1",
"output_dir": "~/Videos", "output_dir": "~/Videos",
"video_codec": "libx264", "video_codec": "libx264",
"audio_codec": "aac", "audio_codec": "aac",
@ -9,5 +9,22 @@
"default_filter": "lanczos", "default_filter": "lanczos",
"enable_faststart": true, "enable_faststart": true,
"auto_timestamp_fix": true, "auto_timestamp_fix": true,
"allow_overwrite": false "allow_overwrite": false,
"logging": {
"enabled": true,
"directory": "~/.local/share/video-tools/logs",
"timestamp_format": "%Y-%m-%d_%H-%M-%S"
},
"profiles": {
"hi-rate": {
"crf": 14,
"preset": "veryslow",
"audio_bitrate": "320k"
},
"portable": {
"crf": 24,
"preset": "faster",
"audio_bitrate": "128k"
}
}
} }

113
docs/CHANGELOG.md Normal file
View File

@ -0,0 +1,113 @@
# docs/CHANGELOG.md
# Changelog
All notable changes to this project will be documented in this file.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
This project adheres to [Semantic Versioning](https://semver.org/).
---
## [0.1.2] - 2025-11-06
### Added
- Relative path headers (`# docs/...`) restored to the top of all documentation files for readability and navigation.
- Updated documentation to reflect:
- `videoinfo` and `--verbose` functionality.
- Logging directory structure with ISO timestamps and `latest.log` symlink.
- Cross-platform (Linux/Windows) compatibility details.
- Added clarification on the `--hi-rate` and `--portable` profiles in `docs/CLI_Functions.md`.
- Added reference to computed bitrate fallback in the upcoming version roadmap.
### Changed
- Documentation standardized for plain-text (Gitea-safe) format.
- Minor corrections to examples and paths in `README.md` and `CLI_Functions.md`.
- Clarified usage of `convert-multiple` and quoting rules for paths with spaces.
- Improved layout consistency across all docs for version parity.
### Planned for 0.1.3
- Computed fallback bitrate in `videoinfo` for older containers (AVI, WMV, MPG).
- Colorized technical output for clarity.
- Header profile label display (Default / High Rate / Portable).
- Automatic configuration detection improvements.
---
## [0.1.1] - 2025-11-05
### Added
- `--hi-rate` and `--portable` profile options:
- High-rate: CRF 14, preset `veryslow`, 320 kbps audio
- Portable: CRF 24, preset `faster`, 128 kbps audio
- `videoinfo` command:
- Displays concise technical details (duration, codecs, resolution, FPS, bitrate, etc.)
- `--verbose` flag outputs full `ffprobe` metadata for debugging
- Automatic log directory:
- `~/.local/share/video-tools/logs/` with ISO-timestamped filenames
- Symlink `latest.log` points to the newest log
- Conversion summary now includes bitrate, FPS, elapsed time, and mux overhead
- Cross-platform compatibility confirmed for Linux and Windows (Git Bash / WSL)
### Changed
- Improved `convert-multiple` handling of spaced file paths
- Cleaner and color-coded CLI output
- Updated internal default values for logging and error messages
- Improved argument parsing for optional profile flags
### Fixed
- Resolved “unbound variable output_name” in `convert_multiple`
- Fixed missing log directory permissions
- Corrected path handling issues on Windows systems
- Ensured temporary concat lists are removed after conversion
---
## [0.1.0] - 2025-11-04
### Added
- Initial release of **Video Tools CLI**
- `convert-single` command:
- Converts a single input file (AVI, MPG, MKV, MOV, etc.) into MP4
- Uses FFmpeg with modern compression (`libx264`, `AAC`, CRF 18)
- Automatically corrects timestamps (`-fflags +genpts`)
- Outputs to `~/Videos`
- `convert-multiple` command:
- Merges multiple video inputs into one MP4
- Re-encodes using same compression settings
- Creates and cleans temporary file lists automatically
- Config system (`config/config.json`) with optional `jq` parsing
- Version tracking via `VERSION` file
- Color-coded CLI feedback for INFO, WARN, ERROR, OK
- Graceful error handling with safe exits and cleanup
- Compatible with:
- Linux (bash / zsh / fish shells)
- Windows (via Git Bash or WSL)
### Documentation
- `docs/README.md` — general usage and installation guide
- `docs/CLI_Functions.md` — detailed command reference
- `docs/Conversion_Settings.md` — technical breakdown of FFmpeg defaults
- `docs/Upscale.md` — planned module outline for future upscaling support
### Build System
- `Makefile` with:
- `install` / `uninstall` / `verify` / `docs` / `help` targets
- Version-aware output and FFmpeg dependency check
- Installs both binary and documentation to system paths
---
## Planned for [0.2.0]
### Added
- `upscale-video` command:
- FFmpeg `lanczos` scaling for 720p / 1080p / 4K
- Optional H.265 (HEVC) encoding for smaller files
- `convert-batch` for folder-wide conversions
- JSON-driven override for per-run configuration (custom CRF, bitrate, etc.)
- Optional parallel encoding support
- Automatic codec detection before re-encoding
### Improvements
- More detailed progress bar during FFmpeg execution
- Unified cross-platform installer for Windows (PowerShell script)
- Expanded error handling and logging to `logs/` directory
---
End of File

View File

@ -1,140 +1,165 @@
# CLI Function Reference # docs/CLI_Functions.md
CLI Function Reference (v0.1.2)
This document describes the available commands in `video-tools.sh`. This document describes the available commands in video-tools.sh.
Each command can be run from any terminal once the tool is installed. Each command can be run from any terminal once the tool is installed.
--- ------------------------------------------------------------
Quick Reference
------------------------------------------------------------
## Quick Reference Command: convert-single
Syntax: video-tools convert-single <input> <output.mp4>
Description: Converts a single video to MP4.
| Command | Syntax | Description | Command: convert-multiple
|----------|---------|-------------| Syntax: video-tools convert-multiple <input1> <input2> ... <output.mp4>
| `convert-single` | `video-tools convert-single <input> <output.mp4>` | Converts a single video to MP4. | Description: Combines multiple video files into one MP4.
| `convert-multiple` | `video-tools convert-multiple <input1> <input2> ... <output.mp4>` | Combines multiple video files into one MP4. |
All outputs are saved in your default `~/Videos` folder. Command: videoinfo
Syntax: video-tools videoinfo <file>
Description: Displays concise technical details for a video.
--- Command: videoinfo --verbose
Syntax: video-tools videoinfo <file> --verbose
Description: Displays full raw ffprobe metadata for advanced debugging.
## Command Details All outputs are saved in your default ~/Videos folder, unless overridden in config/config.json.
### 1. convert-single ------------------------------------------------------------
1. convert-single
------------------------------------------------------------
**Purpose** Purpose:
Convert a single input video file into an MP4 with modern compression and audio standards. Convert a single input video file into an MP4 using modern compression and audio standards.
**Usage** Usage:
```bash video-tools convert-single <input> <output.mp4> [--hi-rate | --portable]
video-tools convert-single <input> <output.mp4>
```
**Example** Examples:
```bash video-tools convert-single "example.avi" "example.mp4"
video-tools convert-single \ video-tools convert-single "movie.avi" "movie_high.mp4" --hi-rate
"/run/media/user/Linux/MyData/Videos/Example Collection/Example Movie Part1.avi" \ video-tools convert-single "clip.avi" "clip_mobile.mp4" --portable
"Example Movie.mp4"
```
**Output** Profiles:
``` Default - CRF 18, preset slow, audio 192k (balanced quality/speed)
/home/user/Videos/Example Movie.mp4 --hi-rate - CRF 14, preset veryslow, audio 320k (maximum quality)
``` --portable - CRF 24, preset faster, audio 128k (mobile optimized)
**Behavior** Behavior:
- Converts older formats (AVI, MPG, MOV, MKV, etc.) into MP4. - Converts older formats (AVI, MPG, MOV, MKV, etc.) into MP4.
- Ensures output uses the H.264 codec (libx264) and AAC audio. - Uses H.264 (libx264) for video and AAC for audio.
- Rebuilds timestamps to avoid sync issues. - Rebuilds timestamps with -fflags +genpts to prevent sync issues.
- Adds `+faststart` flag for quicker playback when streamed or loaded in players. - Adds -movflags +faststart to improve playback and streaming.
- Displays detailed FFmpeg progress and conversion summary.
- Creates timestamped logs in ~/.local/share/video-tools/logs/.
**When to use** When to Use:
- When you want to upgrade old videos to a more efficient format. - To modernize legacy or incompatible video files.
- When a single video wont play on mobile or modern devices. - When playback fails on mobile or modern systems.
- To reduce file size without losing visible quality. - To reduce file size while preserving visible quality.
--- ------------------------------------------------------------
2. convert-multiple
------------------------------------------------------------
### 2. convert-multiple Purpose:
**Purpose**
Combine several clips or discs into one MP4 output file. Combine several clips or discs into one MP4 output file.
**Usage** Usage:
```bash video-tools convert-multiple <input1> <input2> ... <output.mp4> [--hi-rate | --portable]
video-tools convert-multiple <input1> <input2> ... <output.mp4>
```
**Example** Example:
```bash
video-tools convert-multiple \ 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 Part1.avi" \
"/run/media/user/Linux/MyData/Videos/Example Collection/Example Movie Part2.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" "Example Movie Combined.mp4"
```
**Output** Behavior:
``` - Merges all listed videos sequentially into a single MP4.
/home/user/Videos/Example Movie Combined.mp4 - Re-encodes each input using the same profile (default, hi-rate, or portable).
``` - Creates and deletes a temporary concat list automatically.
- Displays each added file and progress in the terminal.
- Ensures the output is playable immediately after completion.
- Logs conversion details in ~/.local/share/video-tools/logs/.
**Behavior** When to Use:
- Reads all listed files in order and merges them seamlessly. - To combine multi-part discs, episodes, or clips.
- Each input is re-encoded using the same H.264/AAC settings. - When producing a single continuous playback file.
- 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. 3. videoinfo
- When creating a single playable MP4 from segmented source material. ------------------------------------------------------------
--- Purpose:
Display detailed technical information about a video file.
## Return Codes Usage:
video-tools videoinfo <file> [--verbose]
| Code | Meaning | Examples:
|------|----------| video-tools videoinfo "movie.mp4"
| 0 | Success | video-tools videoinfo "movie.mp4" --verbose
| 1 | Invalid syntax or missing arguments |
| 2 | FFmpeg execution error |
--- Behavior:
- Without flags: Displays key metadata (duration, codecs, resolution, FPS, bitrate).
- With --verbose: Prints full raw ffprobe data for technical inspection.
- Outputs consistent formatting across platforms (no bc dependency).
- Provides fallback for older files missing embedded bitrate metadata.
- Useful for comparing encoding quality or diagnosing container issues.
## Common Issues ------------------------------------------------------------
Return Codes
------------------------------------------------------------
| Symptom | Cause | Fix | 0 - Success
|----------|--------|----| 1 - Invalid syntax or missing arguments
| Conversion fails immediately | Input path invalid | Ensure file path is correct and quoted | 2 - FFmpeg or ffprobe execution error
| 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 |
--- ------------------------------------------------------------
Common Issues
------------------------------------------------------------
## Planned Additions Symptom: Conversion fails immediately
Cause: Input path invalid
Fix: Ensure full path is correct and quoted properly.
| Command | Description | Symptom: Merge causes sync or timing drift
|----------|-------------| Cause: Source files differ in resolution or frame rate
| `convert-batch` | Convert every video in a folder automatically | Fix: Convert each to MP4 first, then merge.
| `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 |
--- Symptom: Output not found
Cause: FFmpeg encountered an error
Fix: Review the relevant log in ~/.local/share/video-tools/logs/.
## Technical Summary ------------------------------------------------------------
Planned Additions
------------------------------------------------------------
### Conversion Logic convert-batch - Convert every video in a folder automatically.
- Uses FFmpeg with explicit input and output flags: upscale-video - Upscale videos to 720p, 1080p, or 4K using lanczos or ML-based filters.
``` compress-video - Recompress MP4s with HEVC (H.265) or AV1 for reduced size.
ffmpeg -fflags +genpts -i "input" -c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k -movflags +faststart "output" video-compare - Compare bitrate, resolution, and encoding stats between two files.
``` auto-fix - Automatically repair timestamps or rotation metadata before encoding.
- `-fflags +genpts` regenerates presentation timestamps (avoids "Non-monotonic DTS" errors).
- Re-encoding ensures compatibility and stable playback.
### File Safety ------------------------------------------------------------
- Original files are untouched. Technical Summary
- All intermediate list files are removed automatically. ------------------------------------------------------------
- FFmpeg handles SIGINT (Ctrl+C) gracefully—partially written files are still playable.
--- Conversion Logic:
ffmpeg -fflags +genpts -i "input" \
-c:v libx264 -crf 18 -preset slow \
-c:a aac -b:a 192k -movflags +faststart "output"
Notes:
- -fflags +genpts regenerates presentation timestamps (avoids "Non-monotonic DTS" errors).
- Modern codecs ensure full compatibility and efficient compression.
- Re-encoding avoids playback issues caused by legacy container formats.
File Safety:
- Original files remain untouched.
- All intermediate concat lists are deleted automatically.
- FFmpeg handles SIGINT (Ctrl+C) safely — partial outputs remain playable.
------------------------------------------------------------
End of File End of File

View File

@ -1,99 +1,134 @@
# Conversion Settings # docs/Conversion_Settings.md
Conversion Settings (v0.1.2)
This file documents the default FFmpeg parameters used in `video-tools.sh` and explains why they are chosen. This file documents the default FFmpeg parameters used in video-tools.sh and explains why they are chosen.
--- ------------------------------------------------------------
Output Format
------------------------------------------------------------
## Output Format
All conversions produce: All conversions produce:
```
Format: MP4 Format: MP4
Container: MPEG-4 Part 14 Container: MPEG-4 Part 14
Video Codec: H.264 (libx264) Video Codec: H.264 (libx264)
Audio Codec: AAC Audio Codec: AAC
```
MP4 was chosen because: Why MP4:
- Its universally supported across modern devices. - Universally supported across modern devices.
- It balances size and compatibility well. - Balances quality, compression, and compatibility.
- H.264 encoding provides excellent quality at smaller bitrates. - H.264 encoding provides excellent visual quality at modest bitrates.
- AAC audio ensures consistent playback on all major systems including Windows, macOS, Android, and iOS.
--- ------------------------------------------------------------
Default Parameters
------------------------------------------------------------
## Default Parameters Parameter: -c:v libx264
Purpose: H.264 video encoding (modern, efficient, hardware-accelerated)
| Parameter | Value | Purpose | Parameter: -crf 18
|------------|--------|----------| Purpose: Constant Rate Factor for near-lossless quality (lower = higher quality)
| `-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 |
--- Parameter: -preset slow
Purpose: Improves compression efficiency at moderate CPU cost
## Quality vs. File Size Parameter: -c:a aac
Purpose: High-quality audio encoding compatible with most players
The CRF scale (used by FFmpeg) defines quality and compression balance: Parameter: -b:a 192k
Purpose: Balances clarity and file size
| CRF | Description | Typical Use | Parameter: -movflags +faststart
|------|-------------|--------------| Purpose: Optimizes MP4 for streaming and faster playback start
| 1416 | Near lossless | Archival or professional mastering |
| 1820 | High quality | Everyday use, visually lossless |
| 2124 | 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 **4060% smaller** sizes. Parameter: -fflags +genpts
Purpose: Rebuilds timestamps to prevent sync issues with older containers
--- ------------------------------------------------------------
Profile Presets
------------------------------------------------------------
## Why Preset "slow" Default Profile:
CRF 18
Preset slow
Audio 192k
Balanced for visual clarity and efficient storage.
The preset defines encoding effort vs. compression efficiency. Hi-Rate Profile (--hi-rate):
Options range from `ultrafast``veryslow`. CRF 14
Preset veryslow
Audio 320k
Maximum quality, slower encoding, ideal for archiving or high-bitrate content.
- **slow** provides strong compression without extreme CPU time. Portable Profile (--portable):
- Encoding speed is roughly 23× real-time on a midrange CPU. CRF 24
- File sizes are typically 1020% smaller than `medium` preset at the same quality. Preset faster
Audio 128k
Optimized for mobile devices and reduced file sizes.
--- Each profile automatically adjusts encoding parameters to ensure consistent results without user intervention.
## Audio Strategy ------------------------------------------------------------
Quality vs. File Size
------------------------------------------------------------
AAC at 192k is chosen for: The CRF (Constant Rate Factor) scale controls perceived quality versus compression level.
- 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: CRF 1416: Near-lossless (archival or studio preservation)
- `-c:a copy` for untouched audio streams. CRF 1820: High quality (default visual transparency)
- `-b:a 320k` for high-fidelity preservation. CRF 2124: Medium (smaller file size, minimal loss)
CRF 25+: Low quality (fast encoding, visible artifacts)
--- Default CRF: 18
Produces files roughly 4060 percent smaller than original sources with minimal visible loss.
## Color Space & Scaling ------------------------------------------------------------
Preset Choice
------------------------------------------------------------
No scaling is applied by default. Presets define encoding speed versus compression efficiency.
The video retains original resolution and color profile. Range: ultrafast → veryslow
Upscaling and filtering will be handled in a separate command (`upscale-video`) in future versions, with support for: The preset "slow" was chosen because:
- FFmpegs `scale` and `zscale` filters. - Offers a strong balance between speed and compression.
- `lanczos` resampling (for sharp, clean upscale). - Output files are typically 1020 percent smaller than those encoded at "medium".
- Optional integration with ML-based models (Real-ESRGAN, waifu2x). - Encoding speed is roughly two to three times real-time on a midrange CPU.
--- ------------------------------------------------------------
Audio Strategy
------------------------------------------------------------
## Future Additions AAC at 192k is used for:
- Transparent stereo audio for most content.
- Low CPU usage during encoding.
- Roughly two megabytes per minute of stereo content.
| Planned Setting | Description | Future audio options include:
|------------------|-------------| - -c:a copy to preserve original streams when re-encoding is unnecessary.
| `upscale-mode` | Default scaling filter for upscaling tasks | - -b:a 320k for studio-grade sound reproduction.
| `hevc-mode` | Switch to H.265 (libx265) for smaller files | - FLAC or PCM support for lossless audio workflows.
| `audio-pass` | Option to skip audio re-encoding |
| `config.json` | User-editable file to override default values |
--- ------------------------------------------------------------
Color and Resolution
------------------------------------------------------------
No scaling or color adjustments occur unless explicitly requested.
Source resolution, frame rate, and color space (usually bt709) are preserved.
Future command "upscale-video" will support:
- FFmpeg scale and zscale filters.
- Lanczos resampling for high-quality upscales.
- Optional machine-learning upscalers such as Real-ESRGAN or waifu2x.
------------------------------------------------------------
Future Additions
------------------------------------------------------------
upscale-mode Choose default scaling filter for upscaling tasks
hevc-mode Switch to H.265 (libx265) for smaller, more efficient files
audio-pass Skip audio re-encoding when not needed
config.json User-editable configuration to override all defaults
auto-bitrate Compute estimated average bitrate for legacy containers
------------------------------------------------------------
End of File End of File

View File

@ -1,137 +1,153 @@
# Video Tools CLI # docs/README.md
Video Tools CLI (v0.1.2)
A simple command-line utility for video conversion and merging using FFmpeg. A lightweight command-line utility for video conversion, merging, and media inspection using FFmpeg.
Designed for personal use and sharing with friends. Developed by Leak Technologies for efficient local video processing.
Works on both Linux and Windows (via Git Bash or WSL). Fully compatible with Linux and Windows (via Git Bash or WSL).
--- ------------------------------------------------------------
Overview
------------------------------------------------------------
## Overview The tool provides several core commands:
This tool provides two main commands: convert-single Converts a single video to MP4 using high-quality compression.
convert-multiple Combines multiple video clips or discs into one MP4 file.
videoinfo Displays technical details such as bitrate, resolution, codecs, and duration.
videoinfo --verbose Shows full ffprobe metadata for advanced analysis.
| Command | Description | All converted videos are saved to ~/Videos by default.
|----------|-------------| Logs are stored in ~/.local/share/video-tools/logs with ISO timestamps.
| `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 using your package manager:
sudo pacman -S ffmpeg (Arch, Garuda, EndeavourOS)
sudo apt install ffmpeg (Debian, Ubuntu, Mint)
## Requirements Windows:
1. Download FFmpeg from https://ffmpeg.org/download.html
2. Add FFmpeg to your PATH environment variable.
3. Use Git Bash or WSL to execute video-tools.sh.
### Linux ------------------------------------------------------------
Install FFmpeg with your package manager: Installation
```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: 1. Clone or copy the repository:
```bash git clone https://git.leaktechnologies.dev/Leak_Technologies/VideoTools.git
git clone https://github.com/YourName/VideoTools.git cd VideoTools
cd VideoTools
```
2. Make the script executable: 2. Make the script executable:
```bash chmod +x video-tools.sh
chmod +x video-tools.sh
```
3. (Optional) Add it to PATH: 3. (Optional) Add it to your system PATH:
```bash sudo ln -s ~/VideoTools/video-tools.sh /usr/local/bin/video-tools
sudo ln -s ~/VideoTools/video-tools.sh /usr/local/bin/video-tools
```
You can now run it globally: You can now use it globally:
```bash
video-tools convert-single "input.avi" "output.mp4" video-tools convert-single "input.avi" "output.mp4"
```
--- ------------------------------------------------------------
Default Settings
------------------------------------------------------------
## Default Settings Output directory: ~/Videos
Video codec: libx264
Audio codec: aac
Quality (CRF): 18
Preset: slow
Audio bitrate: 192k
| Setting | Value | Description | These defaults balance visual quality and compression efficiency.
|----------|--------|-------------| They are ideal for general use, personal archiving, and local playback.
| 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. For full parameter details, see docs/Conversion_Settings.md.
--- ------------------------------------------------------------
Example Usage
------------------------------------------------------------
## Example Conversions Convert a single file:
video-tools convert-single "/path/to/input.avi" "output.mp4"
### Convert a single AVI file Merge multiple videos:
video-tools convert-multiple "/path/to/part1.avi" "/path/to/part2.avi" "combined.mp4"
```bash Check video info:
video-tools convert-single \ video-tools videoinfo "combined.mp4"
"/run/media/stu/Linux/MyData/Videos/Example Collection/Example Movie Part1.avi" \
"Example Movie.mp4"
```
Output: Verbose mode:
``` video-tools videoinfo "combined.mp4" --verbose
/home/stu/Videos/Example Movie.mp4
```
--- ------------------------------------------------------------
Conversion Profiles
------------------------------------------------------------
### Combine multiple AVI parts into one MP4 Default:
CRF 18, preset slow, 192k audio (balanced quality and speed)
```bash --hi-rate:
video-tools convert-multiple \ CRF 14, preset veryslow, 320k audio (maximum quality)
"/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: --portable:
``` CRF 24, preset faster, 128k audio (mobile optimized)
/home/stu/Videos/Example Movie Combined.mp4
```
--- Profiles can be added after any convert command.
## Troubleshooting Example:
video-tools convert-single "movie.avi" "movie_high.mp4" --hi-rate
| Issue | Cause | Solution | ------------------------------------------------------------
|--------|--------|----------| Troubleshooting
| `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 |
--- Problem: command not found
Cause: Script not linked globally
Fix: Run ./video-tools.sh or create a symlink in /usr/local/bin
## Roadmap Problem: ffmpeg not found
Cause: FFmpeg not installed
Fix: Install it using your system package manager
| Feature | Status | Problem: permission denied
|----------|--------| Cause: Missing executable permission
| convert-single | ✅ Done | Fix: chmod +x video-tools.sh
| convert-multiple | ✅ Done |
| upscale-video | 🔜 Planned |
| batch conversion | 🔜 Planned |
| automatic format detection | 🔜 Planned |
--- Problem: merge fails
Cause: Inputs use different codecs or frame rates
Fix: Convert each input to MP4 first, then merge
## License ------------------------------------------------------------
Roadmap
------------------------------------------------------------
Free for personal use. convert-single Complete
You can modify or share this tool with anyone. convert-multiple Complete
videoinfo Complete
upscale-video Planned
batch conversion Planned
auto format detect Planned
video-compare Planned
config overrides Planned
------------------------------------------------------------
Documentation Index
------------------------------------------------------------
docs/CLI_Functions.md Command reference and usage examples
docs/Conversion_Settings.md Technical breakdown of encoding defaults
docs/CHANGELOG.md Version history and planned updates
docs/Upscale.md Future plans for scaling and ML-based enhancement
------------------------------------------------------------
License
------------------------------------------------------------
Free for personal and educational use.
Redistribution permitted with attribution to Leak Technologies.
------------------------------------------------------------
End of File

View File

@ -1,71 +1,83 @@
# Upscale Module (Planned) # docs/Upscale.md
Upscale Module (Planned) - v0.1.2
The `upscale-video` command will provide loss-minimized video upscaling. The upscale-video command will provide high-quality resolution upscaling with minimal visual loss.
It will begin with traditional FFmpeg filters and later introduce machine learning based upscalers.
--- ------------------------------------------------------------
Overview
------------------------------------------------------------
## Overview The goal of this module is to let users upscale existing videos to standardized modern resolutions such as:
This module will allow upscaling of existing videos to higher resolutions such as:
- 720p (HD) - 720p (HD)
- 1080p (Full HD) - 1080p (Full HD)
- 2160p (4K) - 2160p (4K UHD)
It will use FFmpegs native scaling filters first and optionally integrate machine learning tools later. The first release will use FFmpegs built-in scaling filters including lanczos, bicubic, and spline36.
Future updates will explore GPU and ML-based upscaling options such as Real-ESRGAN and waifu2x.
--- ------------------------------------------------------------
Planned Syntax
------------------------------------------------------------
## Planned Syntax
```bash
video-tools upscale-video <input> <output.mp4> --scale 1920x1080 video-tools upscale-video <input> <output.mp4> --scale 1920x1080
```
Optional parameters: Optional parameters:
``` --scale <WxH> Specify custom resolution
--scale <WxH> Set explicit resolution --filter <name> Choose scaling filter (lanczos, bicubic, spline36, bilinear)
--filter <name> Choose scaling filter (lanczos, bicubic, spline36) --hevc Encode output with H.265 for reduced file size
--hevc Encode using H.265 for smaller output --keep-audio Copy the original audio stream without re-encoding
--keep-audio Copy original audio stream without re-encoding
```
--- ------------------------------------------------------------
Default Behavior
------------------------------------------------------------
## Default Behavior When no scale or filter is provided, the tool will automatically upscale to the next common resolution above the source.
If no resolution is provided, the tool will upscale intelligently to the nearest standard resolution above the input video. Examples:
Input: 960x540 → Output: 1280x720
Input: 1280x720 → Output: 1920x1080
Input: 1440x1080 → Output: 1920x1080
Example: The tool will retain the same aspect ratio and avoid unnecessary stretching or cropping.
- Input: 960×540 → Output: 1280×720
- Input: 1280×720 → Output: 1920×1080
--- ------------------------------------------------------------
Technical Notes
------------------------------------------------------------
## Technical Notes Example FFmpeg usage:
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
### FFmpeg Filter Example Explanation:
scale=1920:1080:flags=lanczos performs resampling using the Lanczos algorithm for sharp, high-quality results.
Lanczos minimizes aliasing and ringing while retaining edge detail.
Future implementations may use zscale for improved color management or GPU-accelerated scaling with CUDA or Vulkan.
```bash ------------------------------------------------------------
ffmpeg -i input.mp4 -vf scale=1920:1080:flags=lanczos \ Planned Features
-c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k output_1080p.mp4 ------------------------------------------------------------
```
- `scale=1920:1080:flags=lanczos` → high-quality resampling FFmpeg scaler (lanczos) Planned
- `lanczos` offers sharp, low-artifact upscale zscale and bicubic scaling Planned
- Later versions may support `zscale` or ML-based filters ML-based upscaling (Real-ESRGAN) Research stage
Auto-resolution detection Planned
GPU acceleration support Planned
Configurable quality presets Planned
HEVC and AV1 encoder options Planned
Batch folder upscaling mode Planned
--- ------------------------------------------------------------
Example Future Commands
------------------------------------------------------------
## Planned Features Upscale to 1080p using default settings:
video-tools upscale-video "movie.mp4" "movie_1080p.mp4"
| Feature | Status | Upscale to 4K using HEVC and Lanczos filter:
|----------|--------| video-tools upscale-video "movie.mp4" "movie_4k.mp4" --scale 3840x2160 --hevc --filter lanczos
| FFmpeg scaler (lanczos) | 🔜 Planned |
| ML-based upscaling (Real-ESRGAN / waifu2x) | 🚧 Research |
| Auto resolution detection | 🔜 Planned |
| GPU acceleration support | 🔜 Planned |
| Configurable presets | 🔜 Planned |
--- Copy original audio without re-encoding:
video-tools upscale-video "documentary.mp4" "documentary_upscaled.mp4" --keep-audio
------------------------------------------------------------
End of File End of File

View File

@ -1,17 +1,19 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# # video-tools.sh
# ----------------------------------------------------------
# Simple FFmpeg CLI Toolset # Simple FFmpeg CLI Toolset
# -------------------------
# Provides easy commands for single or multi-file video conversion. # Provides easy commands for single or multi-file video conversion.
# Works on Linux and Windows (Git Bash / WSL) as long as ffmpeg is installed. # Works on Linux and Windows (Git Bash / WSL) as long as ffmpeg is installed.
# # ----------------------------------------------------------
set -euo pipefail set -euo pipefail
# ========================================================== # ==========================================================
# Configuration system # Configuration system
# ========================================================== # ==========================================================
CONFIG_FILE="$(dirname "$0")/config/config.json" SCRIPT_DIR="$(dirname "$0")"
CONFIG_FILE="$SCRIPT_DIR/config/config.json"
LOG_DIR="$HOME/.local/share/video-tools/logs"
# ------------------------- # -------------------------
# Default configuration # Default configuration
@ -22,7 +24,7 @@ AUDIO_CODEC="aac"
CRF="18" # lower = higher quality CRF="18" # lower = higher quality
PRESET="slow" # slower = better compression PRESET="slow" # slower = better compression
AUDIO_BITRATE="192k" AUDIO_BITRATE="192k"
VERSION="0.1.0" VERSION="0.1.1"
# ========================================================== # ==========================================================
# Utility: Colour logging # Utility: Colour logging
@ -39,7 +41,7 @@ warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
# ========================================================== # ==========================================================
# Check dependencies early # Dependency check
# ========================================================== # ==========================================================
if ! command -v ffmpeg >/dev/null 2>&1; then if ! command -v ffmpeg >/dev/null 2>&1; then
error "ffmpeg is not installed or not in PATH." error "ffmpeg is not installed or not in PATH."
@ -62,6 +64,33 @@ else
fi fi
mkdir -p "$OUTPUT_DIR" || { error "Failed to create output directory $OUTPUT_DIR"; exit 1; } mkdir -p "$OUTPUT_DIR" || { error "Failed to create output directory $OUTPUT_DIR"; exit 1; }
mkdir -p "$LOG_DIR" || { error "Failed to create log directory $LOG_DIR"; exit 1; }
# ==========================================================
# Conversion Profiles
# ==========================================================
apply_profile() {
local profile="$1"
case "$profile" in
hi-rate|--hi-rate)
info "Applying high bitrate profile..."
CRF="14"
PRESET="veryslow"
AUDIO_BITRATE="320k"
;;
portable|--portable)
info "Applying portable/mobile profile..."
CRF="24"
PRESET="faster"
AUDIO_BITRATE="128k"
;;
default|--default|"")
;;
*)
warn "Unknown profile: $profile — ignoring."
;;
esac
}
# ========================================================== # ==========================================================
# Header output # Header output
@ -78,6 +107,81 @@ print_header() {
echo "----------------------------------------------" echo "----------------------------------------------"
} }
# ==========================================================
# Path sanitization (handles spaces, quotes, etc.)
# ==========================================================
safe_path() {
local p="$1"
printf "%s" "$p" | sed "s/'/'\\\\''/g"
}
sanitize_name() {
local name="$1"
echo "$name" | sed 's/[^A-Za-z0-9._-]/_/g'
}
# ==========================================================
# Summary report parser
# ==========================================================
print_summary() {
local log_file="$1"
local input="$2"
local output="$3"
local start_time="$4"
local end_time="$5"
local elapsed=$((end_time - start_time))
local elapsed_min=$((elapsed / 60))
local elapsed_sec=$((elapsed % 60))
local duration bitrate speed fps frames mux_overhead vbitrate abitrate
duration=$(grep -Eo "time=[0-9:.]+" "$log_file" | tail -1 | cut -d= -f2)
bitrate=$(grep -Eo "bitrate=[0-9.]+kbits/s" "$log_file" | tail -1 | awk -F= '{print $2}')
speed=$(grep -Eo "speed=[0-9.]+x" "$log_file" | tail -1 | cut -d= -f2)
fps=$(grep -Eo "fps=[0-9.]+" "$log_file" | tail -1 | cut -d= -f2)
frames=$(grep -Eo "frame=[0-9]+" "$log_file" | tail -1 | awk -F= '{print $2}')
mux_overhead=$(grep -Eo "muxing overhead: [0-9.]+%" "$log_file" | tail -1 | awk '{print $3}')
vbitrate=$(grep -Eo "kb/s:[0-9.]+" "$log_file" | tail -1 | cut -d: -f2)
abitrate=$(echo "$AUDIO_BITRATE" | sed 's/k//')
echo ""
echo "----------------------------------------------"
echo "Conversion Summary"
echo "----------------------------------------------"
echo "Input File : $input"
echo "Output File : $output"
echo "Log File : $log_file"
echo "Duration : ${duration:-unknown}"
echo "Encoding Speed : ${speed:-unknown}"
echo "Elapsed Time : ${elapsed_min}m ${elapsed_sec}s"
echo "Status : ✅ Successful"
echo "----------------------------------------------"
echo "[Technical Stats]"
echo "Average Bitrate : ${bitrate:-N/A}"
echo "Video Bitrate : ${vbitrate:-N/A} kb/s"
echo "Audio Bitrate : ${abitrate:-N/A} kb/s"
echo "Frames Encoded : ${frames:-N/A}"
echo "FPS Achieved : ${fps:-N/A}"
echo "Mux Overhead : ${mux_overhead:-N/A}"
echo "CRF Setting : $CRF"
echo "----------------------------------------------"
echo ""
}
# ==========================================================
# Generate timestamped log file
# ==========================================================
generate_logfile() {
local output_name="$1"
local timestamp
timestamp=$(date +"%Y-%m-%d_%H-%M-%S")
local base
base=$(basename "$output_name" .mp4)
local safe_base
safe_base=$(sanitize_name "$base")
echo "$LOG_DIR/${timestamp}_${safe_base}.log"
}
# ========================================================== # ==========================================================
# Convert one file # Convert one file
# ========================================================== # ==========================================================
@ -85,85 +189,243 @@ convert_single() {
local input="$1" local input="$1"
local output_name="$2" local output_name="$2"
local output_path="$OUTPUT_DIR/$output_name" local output_path="$OUTPUT_DIR/$output_name"
local safe_input
safe_input="$(safe_path "$input")"
local log_file
log_file=$(generate_logfile "$output_name")
local start_time end_time
print_header print_header
info "Converting single video..." info "Converting single video..."
info "Input : $input" info "Input : $input"
info "Output: $output_path" info "Output: $output_path"
info "Log : $log_file"
if [[ ! -f "$input" ]]; then if [[ ! -f "$input" ]]; then
error "Input file not found: $input" error "Input file not found: $input"
exit 1 exit 1
fi fi
start_time=$(date +%s)
ffmpeg -hide_banner -loglevel info -fflags +genpts \ ffmpeg -hide_banner -loglevel info -fflags +genpts \
-i "$input" \ -i "$input" \
-c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \ -c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \
-c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \ -c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \
"$output_path" || { error "Conversion failed."; exit 1; } "$output_path" 2>&1 | tee "$log_file"
end_time=$(date +%s)
ln -sf "$log_file" "$LOG_DIR/latest.log" 2>/dev/null || true
success "Conversion complete: $output_path" success "Conversion complete: $output_path"
print_summary "$log_file" "$safe_input" "$output_path" "$start_time" "$end_time"
} }
# ========================================================== # ==========================================================
# Combine multiple files # Combine multiple files
# ========================================================== # ==========================================================
convert_multiple() { convert_multiple() {
local args=("$@") # Rebuild args array safely to preserve quoted file paths
local args=()
while [[ $# -gt 0 ]]; do
args+=("$1")
shift
done
# Ensure at least two inputs + one output
if [[ ${#args[@]} -lt 3 ]]; then
error "Usage: $0 convert-multiple <input1> <input2> ... <output.mp4> [--hi-rate|--portable]"
exit 1
fi
# Extract and verify output filename
local output_name="${args[-1]}" local output_name="${args[-1]}"
unset 'args[-1]' unset 'args[-1]'
if [[ -z "${output_name:-}" ]]; then
warn "Output name missing — defaulting to combined_output.mp4"
output_name="combined_output.mp4"
fi
# Setup working paths
local list_file local list_file
list_file=$(mktemp) list_file=$(mktemp)
local output_path="$OUTPUT_DIR/$output_name" local output_path="$OUTPUT_DIR/$output_name"
local log_file
log_file=$(generate_logfile "$output_name")
local start_time end_time
print_header print_header
info "Combining multiple videos..." info "Combining multiple videos..."
info "Output: $output_path"
info "Log : $log_file"
# Verify each input and build concat list
for input in "${args[@]}"; do for input in "${args[@]}"; do
if [[ ! -f "$input" ]]; then if [[ ! -f "$input" ]]; then
error "Missing input file: $input" error "Missing input file: '$input'"
rm -f "$list_file" rm -f "$list_file"
exit 1 exit 1
fi fi
echo "file '$input'" >> "$list_file" printf "file '%s'\n" "$(safe_path "$input")" >> "$list_file"
info " + Added: $input" info " + Added: $input"
done done
echo "----------------------------------------------" echo "----------------------------------------------"
# Run FFmpeg and record timing
start_time=$(date +%s)
ffmpeg -hide_banner -loglevel info -f concat -safe 0 -i "$list_file" \ ffmpeg -hide_banner -loglevel info -f concat -safe 0 -i "$list_file" \
-c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \ -c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \
-c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \ -c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \
"$output_path" || { error "Merge failed."; rm -f "$list_file"; exit 1; } "$output_path" 2>&1 | tee "$log_file"
end_time=$(date +%s)
# Cleanup and summary
ln -sf "$log_file" "$LOG_DIR/latest.log" 2>/dev/null || true
rm -f "$list_file" rm -f "$list_file"
success "Combined video created: $output_path" success "Combined video created: $output_path"
print_summary "$log_file" "Multiple inputs" "$output_path" "$start_time" "$end_time"
} }
# ==========================================================
# Show concise or verbose video information (cross-platform)
# ==========================================================
show_videoinfo() {
if ! command -v ffprobe >/dev/null 2>&1; then
error "ffprobe is not installed or not in PATH."
exit 1
fi
if [[ $# -lt 1 ]]; then
error "Usage: $0 videoinfo <file1> [file2 ...] [--verbose]"
exit 1
fi
# Detect verbose flag
local verbose=false
for arg in "$@"; do
[[ "$arg" == "--verbose" ]] && verbose=true
done
for input in "$@"; do
[[ "$input" == "--verbose" ]] && continue
if [[ ! -f "$input" ]]; then
error "File not found: $input"
continue
fi
echo "----------------------------------------------"
echo "File: $input"
echo "----------------------------------------------"
if $verbose; then
ffprobe -v error \
-show_entries format=filename,format_name,duration,size,bit_rate \
-show_streams \
-of default=noprint_wrappers=1:nokey=0 \
"$input" | sed 's/^/ /'
else
# Collect metadata safely
local duration size format vcodec acodec width height fps profile pix_fmt dar sar vbitrate abitrate channels arate bitrate
duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$input")
size=$(ffprobe -v error -show_entries format=size -of default=noprint_wrappers=1:nokey=1 "$input")
format=$(ffprobe -v error -show_entries format=format_name -of default=noprint_wrappers=1:nokey=1 "$input")
bitrate=$(ffprobe -v error -show_entries format=bit_rate -of default=noprint_wrappers=1:nokey=1 "$input")
vcodec=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$input")
profile=$(ffprobe -v error -select_streams v:0 -show_entries stream=profile -of default=noprint_wrappers=1:nokey=1 "$input")
width=$(ffprobe -v error -select_streams v:0 -show_entries stream=width -of default=noprint_wrappers=1:nokey=1 "$input")
height=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of default=noprint_wrappers=1:nokey=1 "$input")
fps=$(ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of default=noprint_wrappers=1:nokey=1 "$input" | awk -F'/' '{if ($2>0) printf "%.2f", $1/$2; else print $1}')
pix_fmt=$(ffprobe -v error -select_streams v:0 -show_entries stream=pix_fmt -of default=noprint_wrappers=1:nokey=1 "$input")
dar=$(ffprobe -v error -select_streams v:0 -show_entries stream=display_aspect_ratio -of default=noprint_wrappers=1:nokey=1 "$input")
sar=$(ffprobe -v error -select_streams v:0 -show_entries stream=sample_aspect_ratio -of default=noprint_wrappers=1:nokey=1 "$input")
vbitrate=$(ffprobe -v error -select_streams v:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 "$input")
acodec=$(ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$input")
abitrate=$(ffprobe -v error -select_streams a:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 "$input")
channels=$(ffprobe -v error -select_streams a:0 -show_entries stream=channels -of default=noprint_wrappers=1:nokey=1 "$input")
arate=$(ffprobe -v error -select_streams a:0 -show_entries stream=sample_rate -of default=noprint_wrappers=1:nokey=1 "$input")
# Compute duration minutes without bc
local mins secs
mins=$(( ${duration%.*} / 60 ))
secs=$(( ${duration%.*} % 60 ))
# Simple size + bitrate formatting (cross-platform safe)
local size_mb=$(( size / 1048576 ))
local bitrate_mbps=$(( bitrate / 1000000 ))
local vbitrate_mbps=$(( vbitrate / 1000000 ))
local abitrate_kbps=$(( abitrate / 1000 ))
echo " Duration: ${duration:-N/A} sec (${mins}m ${secs}s)"
echo " Size: ${size_mb} MB"
echo " Container: ${format:-N/A}"
echo " Video Codec: ${vcodec:-N/A} (${profile:-N/A})"
echo " Resolution: ${width:-N/A}x${height:-N/A} @ ${fps:-N/A} fps"
echo " Aspect Ratio: ${dar:-N/A} (SAR ${sar:-N/A})"
echo " Pixel Format: ${pix_fmt:-N/A}"
echo " Video Bitrate: ${vbitrate_mbps} Mbps"
echo " Audio Codec: ${acodec:-N/A}"
echo " Audio: ${channels:-N/A} ch @ ${arate:-N/A} Hz"
echo " Audio Bitrate: ${abitrate_kbps} kbps"
echo " Overall Rate: ${bitrate_mbps} Mbps"
fi
echo ""
done
}
# ========================================================== # ==========================================================
# Dispatcher # Dispatcher
# ========================================================== # ==========================================================
case "${1:-}" in case "${1:-}" in
convert-single) convert-single)
shift shift
if [[ $# -ne 2 ]]; then if [[ $# -lt 2 ]]; then
error "Usage: $0 convert-single <input> <output.mp4>" error "Usage: $0 convert-single <input> <output.mp4> [--hi-rate|--portable]"
exit 1 exit 1
fi fi
convert_single "$@" # Optional profile flag
if [[ $# -eq 3 ]]; then
apply_profile "${3:-}"
fi
convert_single "$1" "$2"
;; ;;
convert-multiple) convert-multiple)
shift shift
if [[ $# -lt 3 ]]; then if [[ $# -lt 3 ]]; then
error "Usage: $0 convert-multiple <input1> <input2> ... <output.mp4>" error "Usage: $0 convert-multiple <input1> <input2> ... <output.mp4> [--hi-rate|--portable]"
exit 1 exit 1
fi fi
# Handle optional profile flag
last_arg="${@: -1}"
case "$last_arg" in
--hi-rate|--portable)
apply_profile "$last_arg"
set -- "${@:1:$(($#-1))}"
;;
esac
convert_multiple "$@" convert_multiple "$@"
;; ;;
videoinfo|--videoinfo|--fileinfo)
shift
show_videoinfo "$@"
;;
*) *)
echo "Video Tools v$VERSION" echo "Video Tools v$VERSION"
echo "Usage:" echo "Usage:"
echo " $0 convert-single <input> <output.mp4>" echo " $0 convert-single <input> <output.mp4> [--hi-rate|--portable]"
echo " $0 convert-multiple <input1> <input2> ... <output.mp4>" echo " $0 convert-multiple <input1> <input2> ... <output.mp4> [--hi-rate|--portable]"
echo " $0 videoinfo <file1> [file2 ...]"
echo ""
echo "Profiles:"
echo " --hi-rate Highest bitrate and quality (CRF 14, 320k audio)"
echo " --portable Smaller file size for mobile (CRF 24, 128k audio)"
echo "" echo ""
echo "All outputs will be saved in: $OUTPUT_DIR" echo "All outputs will be saved in: $OUTPUT_DIR"
echo "Logs stored in: $LOG_DIR"
;; ;;
esac esac